Weil es aus Versehen notwendig wurde, eine Chat-Anwendung zu implementieren Ich habe untersucht, wie ich eine WebSocket-Anwendung mit Flask implementieren kann.
Ich werde bis zu dem Punkt schreiben, an dem ich versuche, die Probe zu verschieben Dies allein reicht aus, um die Hauptfunktionen des Chats zu nutzen.
Ich werde es auf Flask 'Schulter implementieren Die folgenden zwei Erweiterungen wurden als Optionen aufgeführt.
Es ist ein wenig alt wie im Februar 2014, aber im Erklärenden Artikel von miguelgrinberg Es gibt einen Abschnitt, der den Vergleich zwischen den beiden erklärt.
++++++++++++++++++++++++++++++++++++++++++++++++++
The main difference between Flask-Sockets and Flask-SocketIO is that the former wraps the native WebSocket protocol (through the use of the gevent-websocket project), so it can only be used by the most modern browsers that have native support. Flask-SocketIO transparently downgrades itself for older browsers.
Flask-Sockets verwendet das native WebSocket-Protokoll Durch gevent-Websocket wickeln. Wird nur in modernen Browsern verwendet, die WebSocket nativ unterstützen. Auf der anderen Seite kann Flask-Socket IO mit älteren Browsern verwendet werden.
Another difference is that Flask-SocketIO implements the message passing protocol exposed by the SocketIO Javascript library. Flask-Sockets just implements the communication channel, what is sent on it is entirely up to the application.
Flask-SocketIO ist eine JavaScript SocketIO-Bibliothek Es implementiert ein Protokoll zum Austausch von Nachrichten. Flask-Sockets implementieren nur Kommunikationskanäle Was Sie senden, hängt von der Bewerbung ab.
Flask-SocketIO also creates an environment for event handlers that is close to that of regular view functions, including the creation of application and request contexts. There are some important exceptions to this explained in the documentation, however.
Flask-SocketIO erstellt eine Umgebung für Ereignishandler, die sich in der Nähe von Ansichtsfunktionen befinden. Dies umfasst das Generieren von Anwendungskontexten und Anforderungskontexten. Mit einigen Ausnahmen, wie in der Dokumentation erläutert.
++++++++++++++++++++++++++++++++++++++++++++++++++
Obwohl der dritte Punkt nicht gut übersetzt wurde Ich denke, der Punkt ist, dass es nahtlos in bestehende Flask-Apps implementiert werden kann.
Ich war besorgt über die Zuverlässigkeit des Autors und des Stars von GitHub auf dem gleichen Niveau.
Deshalb habe ich [Flask-SocketIO] gewählt (https://github.com/miguelgrinberg/Flask-SocketIO). Wenn Sie mit dem WebSocket-Protokoll oder auf der Client-Seite (JavaScript) in Kontakt treten möchten Soll ich Flask-Sockets für die Freiheit verwenden?
Es scheint jedoch, dass Sie in beiden Fällen das erreichen können, was Sie tun möchten.
Verwenden Sie den lokalen Docker wie im vorherigen Artikel (http://qiita.com/nanakenashi/items/cbe8e8ef878121638514). Meine Ausführungsumgebung ist Public Beta von Docker für Mac.
Ausführung
$ docker --version
Docker version 1.12.0, build 8eab29e, experimental
Ich verwende Docker nur, um schnell eine Umgebung zu erstellen Wenn Sie eine Umgebung haben, in der neues Python bis zu einem gewissen Grad ausgeführt werden kann, überspringen Sie den Umgebungskonstruktionsteil.
flask_socket/
├ Dockerfile
└ requirements.txt
Dockerfile
#Angeben des Basisbildes
FROM python:3.5.2-alpine
#Speichern Sie das Verzeichnis, in dem sich die Quelle befindet, als Variable
ARG project_dir=/web/socket/
#Installiere git nach dem Aktualisieren von Paketen, die mit apk installiert werden können
RUN apk update
RUN apk add git
# requirements.Installieren Sie das in txt aufgeführte Paket
WORKDIR $project_dir
ADD requirements.txt .
RUN pip install -r requirements.txt
#Flasche aus dem GitHub-Repository-Holen Sie sich den SocketIO-Quellcode
RUN git clone https://github.com/miguelgrinberg/Flask-SocketIO.git Flask-SocketIO
WORKDIR $project_dir/Flask-SocketIO/example
requirements.txt
Nach der Installation von Flask
und Flask-Socket IO
mit Pip
$ pip freeze> require.txt
.
requirements.txt
click==6.6
Flask==0.11.1
Flask-SocketIO==2.6.2
itsdangerous==0.24
Jinja2==2.8
MarkupSafe==0.23
python-engineio==0.9.2
python-socketio==1.4.4
six==1.10.0
Werkzeug==0.11.10
Mit Ausnahme der Pakete, von denen der Körper von "Flask" abhängt
Flask-SocketIO
, python-engineio
, python-socketio
, six
wurden hinzugefügt.
Bilderzeugung
$ cd /path/to/flask_socket/
$ docker build -t flask_socket .
-t flask_socket
: Benennen Sie das zu erstellende Bild 'flask_socket'.
: Verwenden Sie Dockerfile im aktuellen VerzeichnisContainer-Start
$ docker run -p 5000:5000 -it flask_socket /bin/sh
-p 5000: 5000
: Direkter Port 5000 des Hosts zu Port 5000 des Containers-it
: Betreiben Sie den Container mit dem aktuellen Eingabegerätflask_socket
: Angabe des Bildnamens/ bin / sh
: Führen Sie den Befehl sh im gestarteten Container ausFügen Sie dem Anwendungsausführungscode die Einstellung "Host" hinzu.
app.py
# socketio.run(app, debug=True)
socketio.run(app, host='0.0.0.0', debug=True)
Flaschenausführung
$ python app.py
Wenn Sie über Ihren Browser auf localhost: 5000
zugreifen, wird ein Bildschirm wie der folgende angezeigt.
Erläutern Sie einen Teil des Formulars "Senden:"
Echo
: Papagei an den Benutzer zurückgeben, der die Nachricht eingegeben hatBroadcast
: An alle Clients senden (alle Benutzer, die dieselbe Seite geöffnet haben)Disconnect
: Verbindung zum Server trennenDer Unterschied zwischen "Echo" und "Broadcast" kann leicht durch Anordnen der Registerkarten verstanden werden. Andere Elemente werden weggelassen, da sie als Chatroom-bezogene Vorgänge interpretiert werden. Sie können übrigens den Namen des Raums angeben, aber keinen eigenen Namen eingeben.
app.py
#Laden der benötigten Module
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit, join_room, leave_room, \
close_room, rooms, disconnect
#Angabe der Bibliothek, die für die asynchrone Verarbeitung verwendet werden soll
# `threading`, `eventlet`, `gevent`Kann ausgewählt werden aus
async_mode = None
#Erstellen Sie ein Flask-Objekt und geben Sie den Schlüssel für die Verschlüsselung der Sitzungsinformationen an
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
#Flaschenobjekt, asynchron_Erstellen Sie ein SocketIO-Serverobjekt, indem Sie den Modus angeben
socketio = SocketIO(app, async_mode=async_mode)
#Globale Variable zum Speichern von Threads
thread = None
app.py
#Starten Sie den SocketIO-Server im Debug-Modus
socketio.run(app, debug=True)
Die SocketIO-Bibliothek (JavaScript) wird in das Skript in HTML geladen.
index.html
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
Geben Sie danach den Namespace (Endpunkt der WebSocket-Kommunikation) und an Eine Verbindung wird mit dem SocketIO-Server hergestellt.
Angeben von Handlern für Ereignisse, die beim Herstellen einer Verbindung zum Server ausgegeben werden
Hier wird auch der Handler für das Ereignis "Meine Antwort" angegeben.
Die Antwort scheint zu dem Tag hinzugefügt zu werden, das durch den Selektor # log
angegeben wird.
index.html
namespace = '/test';
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
socket.on('connect', function() {
socket.emit('my event', {data: 'I\'m connected!'});
});
socket.on('my response', function(msg) {
$('#log').append('<br>' + $('<div/>').text('Received #' + msg.count + ': ' + msg.data).html());
});
Empfangen Sie auf der Serverseite eine Verbindungsanforderung vom Client mit dem folgenden Code Die Antwort wird zurückgegeben, indem das Ereignis "Meine Antwort" ausgelöst wird. Der Teil von "socketio.start_background_task (target = background_thread)" wird später beschrieben.
app.py
@socketio.on('connect', namespace='/test')
def test_connect():
global thread
if thread is None:
thread = socketio.start_background_task(target=background_thread)
emit('my response', {'data': 'Connected', 'count': 0})
Mit dem obigen Code wird der erste Operationsteil des Antwortprotokolls angezeigt.
Received #0: Connected Received #1: I'm connected!
Durch Schreiben eines Handlers für das Ereignis in Python und JavaScript Ich fand heraus, dass ich eine wechselseitige Interaktion definieren konnte.
Echo / Broadcast hat das Formular-Tag wie folgt beschrieben
index.html
<form id="emit" method="POST" action='#'>
<input type="text" name="emit_data" id="emit_data" placeholder="Message">
<input type="submit" value="Echo">
</form>
<form id="broadcast" method="POST" action='#'>
<input type="text" name="broadcast_data" id="broadcast_data" placeholder="Message">
<input type="submit" value="Broadcast">
</form>
Durch das Senden des Formulars wird der im folgenden Code definierte Handler ausgeführt.
My Event
Event bzw. My Broadcast Event
Ich feuere mit den im Formular eingegebenen Daten.
index.html
$('form#emit').submit(function(event) {
socket.emit('my event', {data: $('#emit_data').val()});
return false;
});
$('form#broadcast').submit(function(event) {
socket.emit('my broadcast event', {data: $('#broadcast_data').val()});
return false;
});
Infolgedessen wird der folgende Code auf der Python-Seite ausgeführt Rückgabe des Ergebnisses durch Auslösen des Ereignisses "Meine Antwort". Fast der gleiche Code ist in einer Reihe, aber im Fall von "Mein Sendeereignis" Indem Sie "Broadcast = True" als Schlüsselwortargument für "emit" eingeben Gibt an, dass die Nachricht an alle Clients gesendet werden soll.
app.py
@socketio.on('my event', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my response',
{'data': message['data'], 'count': session['receive_count']})
@socketio.on('my broadcast event', namespace='/test')
def test_broadcast_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my response',
{'data': message['data'], 'count': session['receive_count']},
broadcast=True)
Im Teil "Durchschnittliche Ping / Pong-Latenz" Es zeigt, wie viel Latenz bei der Kommunikation mit dem Server besteht.
Der folgende Code zeichnet die Kommunikationsstartzeit jede Sekunde auf Ich feuere das "Mein Ping" -Event ab. Die Variable "ping_pong_times" ist ein Array zum Speichern vergangener Kommunikationen.
index.html
var ping_pong_times = [];
var start_time;
window.setInterval(function() {
start_time = (new Date).getTime();
socket.emit('my ping');
}, 1000);
Die Python-Seite feuert "mein Pong" nur als Reaktion auf das Feuer des "mein Ping" -Ereignisses ab.
app.py
@socketio.on('my ping', namespace='/test')
def ping_pong():
emit('my pong')
Nehmen Sie auf der JavaScript-Seite den Unterschied zwischen der Zeit, zu der "mein Pong" abgefeuert wurde, und der Startzeit Der Durchschnitt vergangener Kommunikationsaufzeichnungen wird unter "Durchschnittliche Ping- / Pong-Latenz" angezeigt.
app.py
socket.on('my pong', function() {
var latency = (new Date).getTime() - start_time;
ping_pong_times.push(latency);
ping_pong_times = ping_pong_times.slice(-30); // keep last 30 samples
var sum = 0;
for (var i = 0; i < ping_pong_times.length; i++)
sum += ping_pong_times[i];
$('#ping-pong').text(Math.round(10 * sum / ping_pong_times.length) / 10);
});
Die gesamte Verarbeitung bis zu diesem Punkt begann auf der Clientseite (JavaScript). In Ihrer Anwendung möchten Sie möglicherweise Informationen von der Serverseite übertragen.
Im Beispielcode hatte der Handler für das Ereignis "connect" die folgende Beschreibung:
app.py
thread = socketio.start_background_task(target=background_thread)
Der "Hintergrund_Thread", der "Ziel" ist, ist wie folgt definiert.
app.py
def background_thread():
"""Example of how to send server generated events to clients."""
count = 0
while True:
socketio.sleep(10)
count += 1
socketio.emit('my response',
{'data': 'Server generated event', 'count': count},
namespace='/test')
Sie können sehen, dass alle 10 Sekunden das Ereignis "Meine Antwort" ausgelöst wird. Dies scheint nützlich zu sein, wenn die Zeitleiste automatisch aktualisiert oder eine Anwendung wie Bijin Clock implementiert wird.
Ich habe gerade den Beispielcode gelöscht und gelesen, aber er war hilfreich. Es scheint, dass Sie verschiedene Dinge machen können, indem Sie dies ein wenig ändern.
Obwohl es von nun an notwendig sein wird, den gesamten Quellcode zu lesen Ich denke, Flask hat den Reiz, dass es klein ist, auch wenn es Erweiterungen enthält, und dass es leicht zu halten ist.
Recommended Posts