Parce qu'il est devenu nécessaire de mettre en place une application de chat par accident J'ai étudié comment je pourrais implémenter une application WebSocket à l'aide de Flask.
J'écrirai au point où j'essaye de déplacer l'échantillon Cela suffit à lui seul pour utiliser les principales fonctions du chat.
Je vais l'implémenter sur l'épaule de Flask Les deux extensions suivantes ont été répertoriées comme options.
Il est un peu vieux comme février 2014, mais dans l 'Article explicatif de miguelgrinberg Il y a une section qui explique la comparaison entre les deux.
++++++++++++++++++++++++++++++++++++++++++++++++++
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 utilise le protocole natif WebSocket Emballage via gevent-websocket. Utilisé uniquement dans les navigateurs modernes qui prennent en charge WebSocket de manière native. D'autre part, Flask-Socket IO peut être utilisé avec des navigateurs plus anciens.
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 est une bibliothèque JavaScript SocketIO Il implémente un protocole d'échange de messages. Flask-Sockets n'implémente que des canaux de communication Ce que vous envoyez dépend de l'application.
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 crée un environnement pour les gestionnaires d'événements proches des fonctions d'affichage. Cela inclut la génération de contextes d'application et de contextes de requête. À quelques exceptions près, comme expliqué dans la documentation.
++++++++++++++++++++++++++++++++++++++++++++++++++
Bien que le troisième point n'ait pas été bien traduit Je pense que le fait est qu'il peut être implémenté de manière transparente dans les applications Flask existantes.
J'étais inquiet pour la fiabilité de l'auteur et de la star de GitHub au même niveau.
Par conséquent, j'ai choisi Flask-SocketIO. Si vous souhaitez entrer en contact avec le protocole WebSocket, ou côté client (JavaScript) Dois-je utiliser Flask-Sockets pour la liberté?
Cependant, il semble que vous puissiez réaliser ce que vous voulez faire de toute façon.
Utilisez le Docker local comme dans l'article précédent (http://qiita.com/nanakenashi/items/cbe8e8ef878121638514). Mon environnement d'exécution est la bêta publique de Docker pour Mac.
version
$ docker --version
Docker version 1.12.0, build 8eab29e, experimental
J'utilise juste Docker pour créer rapidement un environnement Si vous avez un environnement dans lequel le nouveau Python peut s'exécuter dans une certaine mesure, ignorez la partie construction de l'environnement.
flask_socket/
├ Dockerfile
└ requirements.txt
Dockerfile
#Spécification de l'image de base
FROM python:3.5.2-alpine
#Stocker le répertoire dans lequel la source est placée en tant que variable
ARG project_dir=/web/socket/
#Installez git après la mise à jour des packages qui peuvent être installés avec apk
RUN apk update
RUN apk add git
# requirements.Installez le package répertorié dans txt
WORKDIR $project_dir
ADD requirements.txt .
RUN pip install -r requirements.txt
#Flask du référentiel GitHub-Obtenir le code source de SocketIO
RUN git clone https://github.com/miguelgrinberg/Flask-SocketIO.git Flask-SocketIO
WORKDIR $project_dir/Flask-SocketIO/example
requirements.txt
Après avoir installé Flask
et Flask-Socket IO
avec pip
$ pip freeze> requirements.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
Sauf pour les paquets dont dépend le corps de Flask
Flask-SocketIO
, python-engineio
, python-socketio
, six
ont été ajoutés.
Création d'image
$ cd /path/to/flask_socket/
$ docker build -t flask_socket .
-t flask_socket
: Nomme l'image à créer'flask_socket '.
: utilise Dockerfile dans le répertoire courantDémarrage du conteneur
$ docker run -p 5000:5000 -it flask_socket /bin/sh
-p 5000: 5000
: port direct 5000 de l'hôte au port 5000 du conteneur-it
: fait fonctionner le conteneur avec le périphérique d'entrée actuelflask_socket
: Spécifier le nom de l'image/ bin / sh
: Exécute la commande sh dans le conteneur démarréAjoutez le paramètre host
au code d'exécution de l'application.
app.py
# socketio.run(app, debug=True)
socketio.run(app, host='0.0.0.0', debug=True)
Exécution du flacon
$ python app.py
Lorsque vous accédez à localhost: 5000
depuis votre navigateur, vous verrez un écran comme celui ci-dessous.
Expliquez une partie du formulaire '' Envoyer: ''
Broadcast
: envoyer à tous les clients (tous les utilisateurs qui ont la même page ouverte)Disconnect
: se déconnecter du serveurLa différence entre «Echo» et «Broadcast» peut être facilement comprise en organisant les onglets. Les autres éléments sont omis car ils sont interprétés comme des opérations liées à la salle de conversation. En passant, vous pouvez spécifier le nom de la salle, mais vous ne pouvez pas entrer votre propre nom.
app.py
#Chargement des modules requis
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit, join_room, leave_room, \
close_room, rooms, disconnect
#Spécification de la bibliothèque à utiliser pour le traitement asynchrone
# `threading`, `eventlet`, `gevent`Peut être sélectionné parmi
async_mode = None
#Créez un objet Flask et spécifiez la clé pour le chiffrement des informations de session
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
#Objet Flask, asynchrone_Créer un objet serveur SocketIO en spécifiant le mode
socketio = SocketIO(app, async_mode=async_mode)
#Variable globale pour stocker les threads
thread = None
app.py
#Démarrez le serveur SocketIO en mode débogage
socketio.run(app, debug=True)
La bibliothèque SocketIO (JavaScript) est chargée dans le script en html.
index.html
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
Après cela, spécifiez l'espace de noms (point de terminaison de la communication WebSocket) et Une connexion est établie avec le serveur SocketIO.
Spécification des gestionnaires pour les événements émis lors de la connexion au serveur
Le gestionnaire de l'événement my response
est également spécifié ici.
La réponse semble être ajoutée à la balise spécifiée par le sélecteur # log
.
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());
});
Côté serveur, recevez une demande de connexion du client avec le code suivant
La réponse est renvoyée en déclenchant l'événement «ma réponse».
La partie de socketio.start_background_task (target = background_thread)
sera décrite plus tard.
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})
Avec le code ci-dessus, la partie de l'opération initiale du journal de réponse s'affiche.
Received #0: Connected Received #1: I'm connected!
En écrivant un gestionnaire pour l'événement à la fois en Python et en JavaScript J'ai trouvé que je pouvais définir une interaction bidirectionnelle.
Echo / Broadcast a la balise Form décrite comme suit
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>
La soumission du formulaire exécute le gestionnaire défini dans le code suivant. Événement «Mon événement» et «mon événement de diffusion» respectivement Je tire avec les données saisies dans le formulaire.
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;
});
En conséquence, le code suivant du côté Python est exécuté
Renvoyer le résultat en déclenchant l'événement my response
.
Presque le même code est aligné, mais dans le cas de "mon événement de diffusion"
En mettant broadcast = True
comme argument de mot-clé pour ʻemit`
Spécifie que le message doit être envoyé à tous les clients.
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)
Dans la partie de "Latence moyenne ping / pong" Il montre la latence de la communication avec le serveur.
Le code ci-dessous enregistre l'heure de début de la communication toutes les secondes
Je déclenche l'événement my ping
.
La variable ping_pong_times
est un tableau pour stocker les communications passées.
index.html
var ping_pong_times = [];
var start_time;
window.setInterval(function() {
start_time = (new Date).getTime();
socket.emit('my ping');
}, 1000);
Le côté Python ne déclenche my pong
qu'en réponse au déclenchement de l'événement my ping
.
app.py
@socketio.on('my ping', namespace='/test')
def ping_pong():
emit('my pong')
Du côté JavaScript, prenez la différence entre l'heure à laquelle mon pong
a tiré et l'heure de début
La moyenne des enregistrements de communication passés est affichée dans «Latence moyenne ping / pong».
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);
});
Tout le traitement jusqu'à ce point a commencé du côté client (JavaScript). Dans votre application, vous souhaiterez peut-être envoyer des informations du côté serveur.
Dans l'exemple de code, le gestionnaire de l'événement connect
avait la description suivante:
app.py
thread = socketio.start_background_task(target=background_thread)
Le "background_thread" qui est "cible" est défini comme suit.
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')
Vous pouvez voir qu'il déclenche l'événement ma réponse
toutes les 10 secondes.
Cela semble utile lors de la mise à jour automatique de la chronologie ou de la mise en œuvre d'une application telle que Bijin Clock.
Je viens de déposer l'exemple de code et de le lire, mais cela a été utile. Il semble que vous puissiez faire diverses choses simplement en le modifiant un peu.
Bien qu'il soit désormais nécessaire de lire l'intégralité du code source Je pense que l'attrait de Flask est qu'il est petit même s'il comprend des extensions, et il est facile de s'y tenir.
Recommended Posts