WebSocket mit Python + uWSGI

Realisieren Sie WebSocket mit Python3.5 + uWSGI

Seit uWSGI 1.9 wird WebSocket wie in [hier] beschrieben (http://uwsgi-docs.readthedocs.io/en/latest/WebSockets.html) unterstützt. Es schien einfach zu sein, und als ich tatsächlich versuchte, die Probe auszuführen, schlug sie viele Male fehl, und nachdem ich sie untersucht und bemerkt hatte, verbrachte ich mehr als einen ganzen Tag. Ursprünglich habe ich versucht, den Inhalt zusammen mit "Nicht blockierend mit Python + uWSGI" zu veröffentlichen, aber er konnte nicht mit derselben Methode realisiert werden, sodass er auch als Memorandum dient. Ich habe beschlossen zu posten.

Umgebung

Führen Sie die folgenden Schritte in der Umgebung aus, in der Python3.5 und Docker installiert sind. Es wurde in einer Mac-Umgebung (macOS Sierra) erstellt.

Verzeichnisaufbau

Die Verzeichnisstruktur ist wie folgt.

スクリーンショット 2017-07-04 0.54.59.png

nginx.conf und nginx.repo unter nginx-python / conf sind "Erstellen Sie eine Umgebung von Python + uWSGI + Nginx mit Docker" Ist das gleiche, so wird es weggelassen. Dort wird auch die grundlegende Verwendung der Befehle docker-compose und docker beschrieben.

Erstellen Sie CRT und KEY für das SSL-Zertifikat

Installiere openssl

Erstellt in einer Mac-Umgebung. Installieren Sie zuerst openssl mit dem Befehl brown.

$ brew install openssl

Wenn Sie den neuesten Befehl "openssl" verwenden, der mit "brown" installiert wurde, fügen Sie der letzten Zeile von ".bashrc" Folgendes hinzu.

~/.bashrc


export PATH=$(brew --prefix openssl)/bin:$PATH

Führen Sie nach dem Hinzufügen Folgendes aus.

$ source ~/.bashrc

Zertifikat erstellen

Ich muss einige Fragen beantworten, wenn ich "csr" erstelle, aber ich habe sie alle als Standard festgelegt (nur die Eingabetaste gedrückt).

$ openssl genrsa -out server.key 2048
$ openssl req -new -key server.key -out server.csr
$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Platzieren Sie die erstellten CRT- und KEY-Dateien im Verzeichnis app (in diesem Beispiel gibt es CSR, dies ist jedoch nicht erforderlich).

Beispielcode

Serverseite

Nachdem der Handshake mit dem Client abgeschlossen ist, wartet er auf den Empfang der Daten und sendet die empfangenen Daten unverändert an den Client.

app/websocket.py


import uwsgi


def application(env, start_response):
    uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', ''))
    msg = uwsgi.websocket_recv()
    print("receive: %s" % msg)
    uwsgi.websocket_send(msg)
    print("end")

Client-Seite

Ein Beispiel, das eine Verbindung zum Server herstellt, Daten sendet und auf eine Antwort wartet, wenn die Taste gedrückt wird.

app/client/index.htm


<!DOCTYPE HTML>
<html>
  <head>
    <script type="text/javascript">
      function WebSocketTest()
      {
        if ("WebSocket" in window) {
          alert("WebSocket is supported by your Browser!");
          var ws = new WebSocket("wss://127.0.0.1:8443/ws/");
          ws.onopen = function() {
            ws.send("Hello from client");
            alert("Message is sent...");
          };
          ws.onmessage = function (evt) {
            var received_msg = evt.data;
            alert("Message is received...");
          };
          ws.onclose = function() {
            alert("Connection is closed...");
          };
        } else {
          alert("WebSocket NOT supported by your Browser!");
        }
      }
    </script>
  </head>
  <body>
    <input type="button" onClick="WebSocketTest();" value="WebSocket Test">
  </body>
</html>

Verschiedene Einstellungsdateien

docker-compose.yml Forward Port Nummer 80 bis 8180 und 443 bis 8443.

docker-compose.yml


version: "2"
services:
  # nginx
  nginx-python:
    build: ./nginx-python
    ports:
      - "8180:80"
      - "8443:443"
    volumes:
      - ./app/:/var/www/html/app/
    environment:
      TZ: "Asia/Tokyo"

Dockerfile Für uWSGI wird git clone erstellt und erstellt. Andernfalls war keine SSL-Verbindung möglich. Auch hier wird angenommen, dass "asyncio" verwendet wird und der nicht blockierende Modus ebenfalls unterstützt wird, aber "WebSocket" kann verwendet werden, selbst wenn der nicht blockierende Modus nicht unterstützt wird. In diesem Fall können Sie "CFLAGS =" - I / usr / include / python3.5m "UWSGI_PROFILE =" asyncio "sicher löschen.

nginx-python/Dockerfile


FROM centos:6.8

ADD ./conf/nginx.repo /etc/yum.repos.d/

# nginx & python
RUN yum localinstall -y http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
RUN yum install -y https://centos6.iuscommunity.org/ius-release.rpm
RUN yum install -y nginx-1.10.1
RUN yum install -y make gcc
RUN yum install -y libxml2-devel
RUN yum install -y python35u python35u-libs python35u-devel python35u-pip
RUN yum clean all

RUN yum install -y git
RUN yum install -y openssl-devel

RUN ln -s /usr/bin/python3.5 /usr/bin/python3 && \
    unlink /usr/bin/python && \
    ln -s /usr/bin/python3 /usr/bin/python && \
    ln -s /usr/bin/pip3.5 /usr/bin/pip && \
    sed -i -e 's/python/python2.6/' /usr/bin/yum

RUN pip install greenlet && \
    cd /root  && \
    git clone https://github.com/unbit/uwsgi.git && \
    cd uwsgi && \
    CFLAGS="-I/usr/include/python3.5m" UWSGI_PROFILE="asyncio" python uwsgiconfig.py --build

# setting nginx
COPY conf/nginx.conf /etc/nginx/nginx.conf
ADD conf/default.conf /etc/nginx/conf.d/default.conf
RUN usermod -u 1000 nginx

EXPOSE 80
EXPOSE 443

ADD ./conf/start.sh /tmp/start.sh

CMD /bin/sh /tmp/start.sh

Ich habe den Inhalt von / usr / bin / yum unterwegs durch den Befehl sed ersetzt, aber wenn ich mit dem Befehl python eine Verknüpfung zu Python 3.5 herstelle, kann yum nicht verwendet werden.

Nginx-Konfigurationsdatei

Ich konnte einfach keinen Weg finden, es mit dem ws -Protokoll ohne Framework zu verwenden. Da es sich um das "wss" -Protokoll handelt, ist der Reverse Proxy so eingestellt, dass er mit "https" zugreift.

nginx-python/conf/default.conf


upstream websocket {
    server localhost:9090;
}

server {
    listen              443;
    server_name         _;
    ssl                 on;
    ssl_certificate     /var/www/html/app/server.crt;
    ssl_certificate_key /var/www/html/app/server.key;

    index index.html index.htm;
    charset utf-8;

    root /var/www/html/app/client;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location /ws/ {
        proxy_pass https://websocket/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location = /favicon.ico {
        empty_gif;
    }
}

Boot-Batch

Wenn Sie "uWSGI" erstellen, um den nicht blockierenden Modus nicht zu verwenden, benötigen Sie die Option "--asyncio 10 --greenlet" nicht (falls angegeben, wird eine Fehlermeldung angezeigt). Es wird auch davon ausgegangen, dass Sie über eine HTTPS-Verbindung darauf zugreifen.

nginx-python/conf/start.sh


#!/bin/sh

/etc/init.d/nginx start
cd /var/www/html/app
chmod -R 777 .
 /root/uwsgi/uwsgi --asyncio 10 --greenlet --logto uwsgi.log --https :9090,server.crt,server.key --http-websockets --wsgi-file websocket.py

Demo

Erstellen Sie und beginnen Sie mit docker-compose up --build. Greifen Sie nach dem normalen Start auf "https: //127.0.0.1: 8443" zu.

スクリーンショット 2017-07-04 1.22.48.png

Wenn Sie auf die Schaltfläche klicken, werden bei jedem Drücken von "OK" nacheinander Warnungen angezeigt, wie unten gezeigt.

スクリーンショット 2017-07-04 1.23.04.png スクリーンショット 2017-07-04 1.23.14.png スクリーンショット 2017-07-04 1.23.27.png スクリーンショット 2017-07-04 1.23.35.png

Darüber hinaus wird Folgendes in das Protokoll auf der Serverseite ausgegeben (hier / var / www / html / app / uwsgi.log).

receive: b'Hello from client'
end

Andere

Ich habe nicht realisiert, was ich ursprünglich ohne Blockierung tun wollte, z. B. den Socket-Empfang als separate Aufgabe zu behandeln, daher möchte ich nicht nur "asyncio", sondern auch "gevent" und "greenlet" untersuchen. .. Der Schmerz ist, dass es nicht viele Informationen über den nicht blockierenden Modus von "uWSGI" und WebSocket gibt.

Recommended Posts

WebSocket mit Python + uWSGI
Nicht blockierend mit Python + uWSGI
FizzBuzz in Python3
Scraping mit Python
Statistik mit Python
Scraping mit Python
Python mit Go
Twilio mit Python
Spielen Sie mit 2016-Python
Getestet mit Python
mit Syntax (Python)
Bingo mit Python
Excel mit Python
Mikrocomputer mit Python
Mit Python besetzen
Erstellen Sie mit Docker eine Python + uWSGI + Nginx-Umgebung
Serielle Kommunikation mit Python
Zip, entpacken mit Python
Django 1.11 wurde mit Python3.6 gestartet
Primzahlbeurteilung mit Python
Python mit Eclipse + PyDev.
Socket-Kommunikation mit Python
Datenanalyse mit Python 2
Scraping in Python (Vorbereitung)
Versuchen Sie es mit Python.
Python lernen mit ChemTHEATER 03
Sequentielle Suche mit Python
"Objektorientiert" mit Python gelernt
Führen Sie Python mit VBA aus
Umgang mit Yaml mit Python
Löse AtCoder 167 mit Python
Serielle Kommunikation mit Python
[Python] Verwenden Sie JSON mit Python
Python lernen mit ChemTHEATER 05-1
Lerne Python mit ChemTHEATER
1.1 Erste Schritte mit Python
Binarisierung mit OpenCV / Python
3. 3. KI-Programmierung mit Python
Kernel-Methode mit Python
Scraping mit Python + PhantomJS
Tweets mit Python posten
Fahren Sie WebDriver mit Python
Verwenden Sie Mecab mit Python 3
Sprachanalyse mit Python
Denken Sie an Yaml mit Python
Kinesis mit Python betreiben
Erste Schritte mit Python
Verwenden Sie DynamoDB mit Python
Zundko Getter mit Python
Hallo Welt mit Nginx + Uwsgi + Python auf EC2
Behandle Excel mit Python
Ohmsches Gesetz mit Python
Primzahlbeurteilung mit Python
Führen Sie Blender mit Python aus
Löse Mathe mit Python
Python ab Windows 7
Erstellen Sie mit Docker eine Umgebung aus Nginx + uWSGI + Python (Django)
Heatmap von Python + matplotlib
Asynchron mit Python verarbeiten
Python-Programmierung mit Atom
Verwenden Sie Python 3.8 mit Anaconda