Flask-SocketIO实现WebSocket双向通信教程

沈亦白
沈亦白
发布时间:2026-10-13| 6人浏览过
原创

本文详解如何利用Flask-SocketIO在Python后端与前端JavaScript之间建立WebSocket双向通信。涵盖HTML5 WebSocket原理、socket.io.js库的使用、前后端事件监听与消息收发机制,以及flask-socketIO的装饰器配置。同时探讨了Manager启动方式可能导致的消息缓存问题,建议直接使用socketio.run以保证实时性。

【flask-socketio】

此前曾探讨过从Web后端向前端推送消息的技术。反向Ajax(Reverse Ajax)是其中一种模式,其核心在于只要客户端与服务器保持交互,服务器就必须维持该客户端的连接请求,并在适当时机返回数据。然而,当客户端数量庞大时,这种维持长连接的方式会消耗巨大的服务器资源,成本较高。

除了反向Ajax,还有隐藏iframe、Comet、长轮询等其他后端推前端的技術。这些技术各有优劣,具体选择需视场景而定,但均未深入展开讨论。

在近期的开发中,遇到一个典型场景:后台执行耗时任务,需实时向前端推送执行进度。若使用反向Ajax,由于消息频率较高,会消耗大量网络资源;且Ajax请求与后台工作进程并行,获取进度可能涉及复杂的进程间通信。因此,理想的方案是后台能随时推送数据,前端实时展示,且后台程序无需阻塞即可继续运行。

为此,可以寻找HTML5引入的WebSocket技术。此外,发现flask-socketio这一扩展模块为Flask框架提供了对WebSocket的支持,恰好满足上述需求。

概述

WebSocket是HTML5定义的一种新协议,支持服务端与客户端进行双向文本或二进制数据通信。它独立于HTTP协议,本质上与HTTP无关,但在形式上仍有相似之处。WebSocket的连接地址格式为ws://localhost:8080,其中协议修饰符为ws而非http。

WebSocket在连接建立阶段通过HTTP握手进行,这是为了兼容浏览器或利用现有功能而采取的折中方案。一旦连接建立,客户端与服务端之间的通信将完全由WebSocket接管,不再使用HTTP协议进行交互。

从资源占用角度看,WebSocket可能比Ajax占用更多资源,但其实现的全双工通信特性使得前后端交互程序的编写更加便捷。由于采用了新协议,需要对前后端代码进行相应改造。

前端WebSocket编写及socket.io.js

由于WebSocket是较新的技术,并非所有浏览器都支持。因此,可以使用以下代码判断浏览器是否支持WebSocket:

if ('WebSocket' in window){
 websocket = new WebSocket('ws://localhost:8080');
}

仅当浏览器支持WebSocket时,才启动相应的处理逻辑。

实现双向通信本身并非最终目的,关键在于通信过程中前后端能执行特定动作,这需要添加事件监听。在前端,可以通过为WebSocket对象绑定监听回调接口,规定在不同场景下前端执行的操作。例如:

wesocket.onopen = function(){
  alert('建立websocket连接');
}

websocket.onerror = function(){
  alert('WebSocket连接发生错误');
}

/****
等等,由于有封装程度更高的js模块,就不扩展写从较底层构建websocket的方法了
****/

socket.io.js

若觉得底层实现繁琐,可以使用封装好的WebSocket JS库,如socket.io.js。该库虽主要为Node.js设计(网上相关教程多结合Node.js),但单独使用亦无不可。若通过CDN引用,可编写如下代码:

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>

应用socket.io.js创建简单Socket对象的代码如下:

var websocket_url = 'http"//' + document.domain + ':' + location.port + '/testnamespace';
//没错是用http开头的url了,因为这个库会自动解析并帮我们创建websocket对象的
//最后的namespace是websocket中的命名空间,后面再讲
var socket = io.connect(wesocket_url);

获得Socket对象后,即可进行消息收发。简单的消息收发示例如下:

//发送消息
socket.emit('request_for_response',{'param':'value'});
//监听回复的消息
socket.on('response',function(data){
  if (data.code == '200'){
    alert(data.msg);
  }
  else{
    alert('ERROR:' + data.msg);
  }
});

其中'request_for_response'和'reponse'为自定义的事件名,需与后端对应名称保持一致以确保通信成功。此外,涉及命名空间(namespace)的概念,消息收发均在'testnamespace'这一特定空间内进行,因此后端也必须配置相同的命名空间。

后端Socket编写(flask-socketio)

此处以Python后端为例。Python中有socketio模块,但直接编写底层代码较为僵硬。鉴于各类Web框架对WebSocket的支持日益完善,这里选用Flask框架的flask-socketio扩展。

flask-socketIO的创建与运行方式如下:

from flask import Flask 
from flask_socketio import SocketIO,emit
app = Flask(__name__)
socketio = SocketIO()
socketio.init_app(app)
"""
对app进行一些路由设置
"""
"""
对socketio进行一些监听设置
"""
if __name__ == '__main__':
  socketio.run(app,debug=True,host='0.0.0.0',port=5000)
  #这里就不再用app.run而用socketio.run了。socketio.run的参数和app.run也都差不多

上述代码中,App的路由设置不再赘述,重点在于SocketIO的监听设置,这直接关乎前后端WebSocket通信。结合前端代码,SocketIO的监听设置可如下配置:

@socketio.on('request_for_response',namespace='/testnamespace')
def give_response(data):
  value = data.get('param')
  #进行一些对value的处理或者其他操作,在此期间可以随时会调用emit方法向前台发送消息
  emit('response',{'code':'200','msg':'start to process...'})
  time.sleep(5)
  emit('response',{'code':'200','msg':'processed'})

SocketIO同样采用类似app.route的装饰器形式进行监听设置,主要参数包含namespace,用于指定监听范围。在前端,只有注册在testnamespace上的Socket,向'request_for_response'发送的消息才会被此函数接收处理。处理函数自带一个参数,用于接收前端emit消息中的对象,并在函数内解析处理。随后,后端通过emit方法向前端发送'start to process'消息,并指定监听事件为'response'。这意味着前端在'response'上的监听处理函数将处理该消息(同样在testnamespace框架内)。发出消息后,后端不会被阻塞,而是继续向下执行。在处理5秒后,后端发出结束处理的消息,前端在等待5秒后接收该消息。

Socket监听响应函数本身无需返回值,只需在处理过程中的适当位置调用emit发送消息即可。

网上部分教程建议使用send方法替代emit(无论前端还是后端)。实际上,send方法是将'request_for_response'和'response'这两个标识默认设为'message'。这样编写时无需指定事件名,直接传递参数即可。反之,使用emit方法相当于执行自定义事件,灵活性更高。

略大项目中Manager的支持

通常,上述socketio.run方式给人的感觉仅适用于小型项目。若开发大型项目,需采用更高级的启动方式,并配置独立的config.py,通过app.config.from_object方法填充配置。

然而,经实验发现,虽然使用manager.run可使socketio工作,但似乎存在类似缓存的机制。即后台emit发出的信息并非直接发送到前端,而是在整个响应函数执行结束后一次性发送。这可能是后端发送时的缓存,也可能是前端接收时的缓存所致。

因此,若使用WebSocket,建议尽量采用socketio.run这种方式启动。配置可通过在socketio.run中添加类似debug=current_app.config['DEBUG'], host=current_app.config['HOST']的参数来实现。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。