Flask-SocketIO 简单使用指南

Flask-SocketIO 使 Flask 应用程序能够访问客户端和服务器之间的低延迟双向通信。客户端应用程序可以使用 Javascript,C ++,Java 和 Swift 中的任何 SocketIO 官方客户端库或任何兼容的客户端来建立与服务器的永久连接。

安装

直接使用 pip 来安装:

pip install flask-socketio
复制代码

要求

Flask-SocketIO 兼容 Python 2.7 和 Python 3.3+。可以从以下三个选项中选择此程序包所依赖的异步服务:

  • eventlet 性能最佳,支持长轮询和 WebSocket 传输。
  • gevent 在许多不同的配置中得到支持。gevent 包完全支持长轮询传输,但与 eventlet 不同,gevent 没有本机 WebSocket 支持。要添加对 WebSocket 的支持,目前有两种选择:安装 gevent-websocket 包为 gevent 增加 WebSocket 支持,或者可以使用带有 WebSocket 功能的 uWSGI Web 服务器。gevent 的使用也是一种高性能选项,但略低于 eventlet。
  • 也可以使用基于 Werkzeug 的 Flask 开发服务器,但需要注意的是,它缺乏其他两个选项的性能,因此它只应用于简单的开发环境。此选项仅支持长轮询传输。

扩展会根据安装的内容自动检测要使用的异步框架。优先考虑 eventlet,然后是 gevent。对于 gevent 中的WebSocket 支持,首选 uWSGI,然后是 gevent-websocket。如果既未安装 eventlet 也未安装 gevent,则使用 Flask 开发服务器。

如果使用多个进程,则进程使用消息队列服务来协调诸如广播之类的操作。支持的队列是 Redis,RabbitMQ以及 Kombu 软件包支持的任何其他消息队列 。

在客户端,官方 Socket.IO Javascript 客户端库可用于建立与服务器的连接。还有使用 Swift,Java 和 C ++ 编写的官方客户端。非官方客户端也可以工作,只要它们实现 Socket.IO协议。

初始化

以下代码示例演示如何将 Flask-SocketIO 添加到 Flask 应用程序:

from flask import Flask, render_template
from flask_socketio import SocketIOapp = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)if __name__ == '__main__':socketio.run(app, host='0.0.0.0', debug=True)
复制代码

以上代码即完成了一个简单的 Web 服务器。

socketio.run()函数封装了 Web 服务器的启动,并替换了app.run()标准的 Flask 开发服务器启动。

当应用程序处于调试模式时,Werkzeug 开发服务器仍然在内部使用和配置正确socketio.run()

在生产模式中,如果可用,则使用 eventlet Web 服务器,否则使用 gevent Web 服务器。如果未安装 eventlet 和gevent,则使用 Werkzeug 开发 Web 服务器。

基于 Flask 0.11 中引入的单击的命令行界面。此扩展提供了适用于启动 Socket.IO 服务器的新版本命令。用法示例:flask run

$ FLASK_APP=my_app.py flask run
复制代码

或者直接使用下面方式,也可以启动项目:

$ python2.7 app.py
复制代码

连接事件

Flask-SocketIO 调度连接和断开事件。以下示例显示如何为它们注册处理程序:

@socketio.on('connect', namespace='/test')
def test_connect():emit('my response', {'data': 'Connected'})@socketio.on('disconnect', namespace='/test')
def test_disconnect():print('Client disconnected')
复制代码

连接事件处理程序可以选择返回False以拒绝连接。这样就可以在此时对客户端进行身份验证。

请注意,连接和断开连接事件将在使用的每个命名空间上单独发送。

接收消息

使用 SocketIO 时,双方都会将消息作为事件接收。在客户端使用 Javascript 回调。使用 Flask-SocketIO,服务器需要为这些事件注册处理程序,类似于视图函数处理路由的方式。

以下示例为未命名的事件创建服务器端事件处理程序:

@socketio.on('message')
def handle_message(message):print('received message: ' + message)
复制代码

上面的示例使用字符串消息。另一种类型的未命名事件使用 JSON 数据:

@socketio.on('json')
def handle_json(json):print('received json: ' + str(json))
复制代码

最灵活的方式是使用自定义事件名称,在开发过程中最常用的也是这种方式。

事件的消息数据可以是字符串,字节,整数或 JSON:

@socketio.on('my event')
def handle_my_custom_event(json):print('received json: ' + str(json))
复制代码

自定义命名事件也可以支持多个参数:

@socketio.on('my event')
def handle_my_custom_event(arg1, arg2, arg3):print('received args: ' + arg1 + arg2 + arg3)
复制代码

Flask-SocketIO 支持 SocketIO 命名空间,允许客户端在同一物理套接字上复用多个独立连接:

@socketio.on('my event', namespace='/test')
def handle_my_custom_namespace_event(json):print('received json: ' + str(json))
复制代码

如果未指定名称空间,'/'则使用具有名称的默认全局名称空间 。

对于装饰器语法不方便的情况,on_event可以使用该方法:

def my_function_handler(data):passsocketio.on_event('my event', my_function_handler, namespace='/test')
复制代码

客户端可以请求确认回叫,确认收到他们发送的消息。处理函数返回的任何值都将作为回调函数中的参数传递给客户端:

@socketio.on('my event')
def handle_my_custom_event(json):print('received json: ' + str(json))return 'one', 2
复制代码

在上面的示例中,将使用两个参数调用客户端回调函数,'one'2。如果处理程序函数未返回任何值,则将调用客户端回调函数而不带参数。

发送消息

如上一节所示定义的 SocketIO 事件处理程序可以使用send()emit() 函数将回复消息发送到连接的客户端。

以下示例将收到的事件退回给发送它们的客户端:

from flask_socketio import send, emit@socketio.on('message')
def handle_message(message):send(message)@socketio.on('json')
def handle_json(json):send(json, json=True)@socketio.on('my event')
def handle_my_custom_event(json):emit('my response', json)
复制代码

注意如何send()emit()分别用于无名和命名事件。

当有命名空间的工作,send()emit()默认使用传入消息的命名空间。可以使用可选namespace参数指定不同的命名空间:

@socketio.on('message')
def handle_message(message):send(message, namespace='/chat')@socketio.on('my event')
def handle_my_custom_event(json):emit('my response', json, namespace='/chat')
复制代码

要发送具有多个参数的事件,请发送元组:

@socketio.on('my event')
def handle_my_custom_event(json):emit('my response', ('foo', 'bar', json), namespace='/chat')
复制代码

SocketIO 支持确认回调,确认客户端收到了一条消息:

def ack():print 'message was received!'@socketio.on('my event')
def handle_my_custom_event(json):emit('my response', json, callback=ack)
复制代码

使用回调时,Javascript 客户端会收到一个回调函数,以便在收到消息时调用。客户端应用程序调用回调函数后,服务器将调用相应的服务器端回调。如果使用参数调用客户端回调,则这些回调也作为服务器端回调的参数提供。

广播

SocketIO 的另一个非常有用的功能是广播消息。SocketIO 支持通过此功能broadcast=True可选参数send()emit()

@socketio.on('my event')
def handle_my_custom_event(data):emit('my response', data, broadcast=True)
复制代码

在启用广播选项的情况下发送消息时,连接到命名空间的所有客户端都会接收它,包括发件人。如果未使用名称空间,则连接到全局名称空间的客户端将收到该消息。请注意,不会为广播消息调用回调。

在此处显示的所有示例中,服务器响应客户端发送的事件。但对于某些应用程序,服务器需要是消息的发起者。这对于向客户端发送通知在服务器中的事件(例如在后台线程中)非常有用。socketio.send()socketio.emit()方法可用于广播到所有连接的客户端:

def some_function():socketio.emit('some event', {'data': 42})
复制代码

请注意,socketio.send()socketio.emit()在上下文理解上和send()emit()功能不同。另请注意,在上面的用法中没有客户端上下文,因此broadcast=True是默认的,不需要指定。

房间

对于许多应用程序,有必要将用户分组为可以一起寻址的子集。最好的例子是具有多个房间的聊天应用程序,其中用户从他们所在的房间接收消息,而不是从其他用户所在的其他房间接收消息。SocketIO 支持通过房间的概念join_room()leave_room()功能:

from flask_socketio import join_room, leave_room@socketio.on('join')
def on_join(data):username = data['username']room = data['room']join_room(room)send(username + ' has entered the room.', room=room)@socketio.on('leave')
def on_leave(data):username = data['username']room = data['room']leave_room(room)send(username + ' has left the room.', room=room)
复制代码

send()emit()函数接受一个可选room导致被发送到所有的都在定房客户端的消息的说法。

所有客户端在连接时都会被分配一个房间,以连接的会话ID命名,可以从中获取request.sid。给定的客户可以加入任何房间,可以给出任何名称。当客户端断开连接时,它将从其所在的所有房间中删除。无上下文socketio.send()socketio.emit()函数也接受一个room参数,以广播给房间中的所有客户端。

由于为所有客户端分配了个人房间,为了向单个客户端发送消息,客户端的会话 ID 可以用作房间参数。

错误处理

Flask-SocketIO还可以处理异常:

@socketio.on_error()        # Handles the default namespace
def error_handler(e):pass@socketio.on_error('/chat') # handles the '/chat' namespace
def error_handler_chat(e):pass@socketio.on_error_default  # handles all namespaces without an explicit error handler
def default_error_handler(e):pass
复制代码

错误处理函数将异常对象作为参数。

还可以使用request.event变量检查当前请求的消息和数据参数,这对于事件处理程序外部的错误记录和调试很有用:

from flask import request@socketio.on("my error event")
def on_my_event(data):raise RuntimeError()@socketio.on_error_default
def default_error_handler(e):print(request.event["message"]) # "my error event"print(request.event["args"])    # (data,)
复制代码

基于类的命名空间

作为上述基于装饰器的事件处理程序的替代,属于命名空间的事件处理程序可以创建为类的方法。flask_socketio.Namespace作为基类提供,用于创建基于类的命名空间:

from flask_socketio import Namespace, emitclass MyCustomNamespace(Namespace):def on_connect(self):passdef on_disconnect(self):passdef on_my_event(self, data):emit('my_response', data)socketio.on_namespace(MyCustomNamespace('/test'))
复制代码

使用基于类的命名空间时,服务器接收的任何事件都将调度到名为带有on_前缀的事件名称的方法。例如,事件my_event将由名为的方法处理on_my_event。如果收到的事件没有在命名空间类中定义的相应方法,则忽略该事件。基于类的命名空间中使用的所有事件名称必须使用方法名称中合法的字符。

为了方便在基于类的命名空间中定义的方法,命名空间实例包括类中的几个方法的版本,flask_socketio.SocketIOnamespace没有给出参数时,这些方法 默认为正确的命名空间。

如果事件在基于类的命名空间中具有处理程序,并且还有基于装饰器的函数处理程序,则仅调用修饰的函数处理程序。

测试

以上是作为官网文档的翻译,下面来说说写完了代码之后,应该怎么来调试。

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">var socket = io.connect('http://' + document.domain + ':' + location.port);socket.on('connect', function() {socket.emit('my event', {data: 'I\'m connected!'});});
</script>
复制代码

使用 JavaScript 来连接服务端,这里说一个我遇到的问题,最开始使用的是 jsbin 来测试,但怎么都连不到后端,原因就是 jsbin 是 HTTPS 的,而我的请求是 HTTP,于是还是老老实实写了一个 HTML 文件,源码可以直接在 Github 下载。

<!DOCTYPE HTML>
<html>
<head><title>Flask-SocketIO Test</title><script type="text/javascript" src="//code.jquery.com/jquery-1.4.2.min.js"></script><script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script><script type="text/javascript" charset="utf-8">$(document).ready(function() {namespace = '/test';var socket = io.connect(location.protocol + '//' + 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());});$('form#emit').submit(function(event) {socket.emit('my_event', {data: $('#emit_data').val()});return false;});});</script>
</head>
<body><h1>Flask-SocketIO Test</h1><p>Async mode is: <b>{{ async_mode }}</b></p><h2>Send:</h2><form id="emit" method="POST" action='#'><input type="text" name="emit_data" id="emit_data" placeholder="Message"><input type="submit" value="Echo"></form><h2>Receive:</h2><div id="log"></div>
</body>
</html>
复制代码

有了这个页面之后,就可以直接在浏览器中输入 http://127.0.0.1:5000 访问服务端了,更多功能可以随意折腾。



相关文档:

github.com/miguelgrinb…

flask-socketio.readthedocs.io/en/latest/

windrocblog.sinaapp.com/?p=1628

zhuanlan.zhihu.com/p/31118736

letus.club/2016/04/10/…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/389340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STL-开篇

基本概念 STL&#xff1a; Standard Template Library&#xff0c;标准模板库 定义&#xff1a; c引入的一个标准类库 特点&#xff1a;1&#xff09;数据结构和算法的 c实现&#xff08; 采用模板类和模板函数&#xff09;2&#xff09;数据的存储和算法的分离3&#xff09;高…

Symbol Mc1000 声音的设置以及播放

首先引用Symbol.Audio 加一命名空间using Symbol.Audio; /声音设备的设置 //Select Device from device list Symbol.Audio.Device MyDevice (Symbol.Audio.Device)Symbol.StandardForms.SelectDevice.Select( Symbol.Audio.Controller.Title, Symbol.Audio.Devic…

/bin/bash^M: 坏的解释器: 没有那个文件或目录

在win下编辑的时候&#xff0c;换行结尾是\n\r &#xff0c; 而在linux下 是\n&#xff0c;所以会多出来一个\r&#xff0c;这样会出现错误 此时执行 sed -i s/\r$// file.sh 将file.sh中的\r都替换为空白&#xff0c;问题解决转载于:https://www.cnblogs.com/zzdbullet/p/9890…

rcp rapido_为什么气流非常适合Rapido

rcp rapidoBack in 2019, when we were building our data platform, we started building the data platform with Hadoop 2.8 and Apache Hive, managing our own HDFS. The need for managing workflows whether it’s data pipelines, i.e. ETL’s, machine learning predi…

pandas处理丢失数据与数据导入导出

3.4pandas处理丢失数据 头文件&#xff1a; import numpy as np import pandas as pd丢弃数据部分&#xff1a; dates pd.date_range(20130101,periods6) df pd.DataFrame(np.random.randn(6,4),indexdates,columns[A,B,C,D]) df.iloc[0,1] np.nan df.iloc[1,2] np.nanp…

Mysql5.7开启远程

2019独角兽企业重金招聘Python工程师标准>>> 1.注掉bind-address #bind-address 127.0.0.1 2.开启远程访问权限 grant all privileges on *.* to root"xxx.xxx.xxx.xxx" identified by "密码"; 或 grant all privileges on *.* to root"%…

分类结果可视化python_可视化分类结果的另一种方法

分类结果可视化pythonI love good data visualizations. Back in the days when I did my PhD in particle physics, I was stunned by the histograms my colleagues built and how much information was accumulated in one single plot.我喜欢出色的数据可视化。 早在我获得…

算法组合 优化算法_算法交易简化了风险价值和投资组合优化

算法组合 优化算法Photo by Markus Spiske (left) and Jamie Street (right) on UnsplashMarkus Spiske (左)和Jamie Street(右)在Unsplash上的照片 In the last post, we saw how actual algorithms are developed and tested. In this post, we will figure out the level of…

Symbol Mc1000 快捷键 的 设置 事件 开发

switch (e.KeyCode) { ///数据 case Keys.F1://清除数据 if(File.Exists("Storage Card/CG.sdf")) { Mc.gConn.Close(); Mc.gConn.Dispose(); File.Delete("Storage Card/CG.sdf"); } MessageBox.S…

pandas合并concatmerge和plot画图

3.6&#xff0c;3.7pandas合并concat&merge 头文件&#xff1a; import pandas as pd import numpy as npconcat基础合并用法 df1 pd.DataFrame(np.ones((3,4))*0,columns [a,b,c,d]) df2 pd.DataFrame(np.ones((3,4))*1,columns [a,b,c,d]) df3 pd.DataFrame(np.ones…

Android跳转WIFI界面的四种方式

第一种 Intent intent new Intent(); intent.setAction("android.net.wifi.PICK_WIFI_NETWORK"); startActivity(intent); 第二种 startActivity(new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS)); 第三种 Intent i new Intent(); if(android.os.Buil…

PS抠发丝技巧 「选择并遮住…」

PS抠发丝技巧 「选择并遮住…」 现在的海报设计&#xff0c;大多数都有模特MM&#xff0c;然而MM的头发实用太多了&#xff0c;有的还飘起来…… 对于设计师(特别是淘宝美工)没有一个强大、快速、实用的抠发丝技巧真的混不去哦。而PS CC 2017版本开始&#xff0c;就有了一个强大…

covid 19如何重塑美国科技公司的工作文化

未来 &#xff0c; 技术 &#xff0c; 观点 (Future, Technology, Opinion) Who would have thought that a single virus would take down the whole world and make us stay inside our homes? A pandemic wave that has altered our lives in such a way that no human (bi…

Symbol Mc1000 Text文本阅读器整体代码

using System; using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Collections;using System.IO;namespace text{ /// <summary> /// Form1 的摘要说明。 /// </summary> public c…

python生日悖论分析_生日悖论

python生日悖论分析If you have a group of people in a room, how many do you need to for it to be more likely than not, that two or more will have the same birthday?如果您在一个房间里有一群人&#xff0c;那么您需要多少个才能使两个或两个以上的人有相同的生日&a…

统计0-n数字中出现k的次数

/*** 统计0-n数字中出现k的次数&#xff0c;其中k范围为0-9 */ public static int countOne(int k, int n) {if (k > n) {return 0;}int sum 0;int right 0;for (int i 0; n > 0; i) {int last n % 10;sum last * i * (int) Math.pow(10, i - 1);if (k 0) {sum - (…

房价预测 search Search 中对数据预处理的学习

对于缺失的数据&#xff1a; 我们对连续数值的特征做标准化&#xff08;standardization&#xff09;&#xff1a;设该特征在整个数据集上的均值为 μ &#xff0c;标准差为 σ 。那么&#xff0c;我们可以将该特征的每个值先减去 μ 再除以 σ 得到标准化后的每个特征值。对于…

3.6.1.非阻塞IO

本节讲解什么是非阻塞IO&#xff0c;如何将文件描述符修改为非阻塞式 3.6.1.1、阻塞与非阻塞 &#xff08;1&#xff09;阻塞是指函数调用会被阻塞。本质是当前进程调用了函数&#xff0c;进入内核里面去后&#xff0c;因为当前进程的执行条件不满足&#xff0c;内核无法里面完…

rstudio 管道符号_R中的管道指南

rstudio 管道符号R基础知识 (R Fundamentals) Data analysis often involves many steps. A typical journey from raw data to results might involve filtering cases, transforming values, summarising data, and then running a statistical test. But how can we link al…