目录
- 什么是 Socket.IO?
python-socketio库简介- 安装
- 核心概念
- 事件
- 房间
- 命名空间
- 快速入门:一个简单的 "Hello, World" 示例
- 服务器端 编程
- 创建服务器
- 事件处理 (
on,emit) - 加入/离开房间 (
enter_room,leave_room) - 向房间广播 (
emit,send) - 处理连接和断开 (
connect,disconnect) - 异步事件处理 (使用
asyncio)
- 客户端 编程
- 创建客户端
- 连接服务器
- 发送和接收事件 (
emit,on)
- 与 Web 框架集成
- Flask
- Django
- FastAPI
- 高级特性
- 认证
- 自定义传输器
- 跨域资源共享
- 常见问题与最佳实践
什么是 Socket.IO?
Socket.IO 是一个基于 JavaScript 的库,用于在浏览器和服务器之间实现实时、双向的通信,它不仅仅是 WebSocket 的一个简单封装,而是一个功能丰富的协议,具有以下特点:

- 回退机制:如果浏览器不支持 WebSocket,它会自动降级到长轮询。
- 断线重连:连接断开后,客户端会自动尝试重新连接。
- 事件系统:支持命名空间和房间,方便进行消息广播和分组。
- 简单易用:API 设计非常直观,易于上手。
python-socketio 是该协议的 Python 实现,让你可以用 Python 编写 Socket.IO 服务器。
python-socketio 库简介
该库由两个主要部分组成:
socketio.Server: 用于构建服务器端,它处理所有 Socket.IO 协议细节,如事件路由、连接管理、房间管理等。socketio.Client: 用于构建客户端,它允许 Python 脚本作为 Socket.IO 客户端连接到其他服务器。
安装
你可以使用 pip 来安装 python-socketio,为了支持 WebSocket,通常还需要安装 engineio。
# 安装核心库 pip install python-socketio # 如果需要支持 WebSocket,请安装 engineio # python-socketio 的依赖会自动处理,但明确安装也无妨 pip install python-engineio # 如果你打算集成到 Flask,可以安装 flask-socketio pip install flask-socketio # 对于 FastAPI,可以使用 python-socketio[asyncio] pip install "python-socketio[asyncio]"
核心概念
事件
通信的基本单位,服务器和客户端通过发送和接收事件来传递数据,每个事件都有一个字符串名称。

- 发送事件:
emit('event_name', data) - 接收事件:
@sio.on('event_name')
房间
将客户端分组到虚拟的“房间”中,你可以向特定房间内的所有客户端广播消息,而无需知道它们的具体 ID,这对于实现聊天室、游戏大厅等场景非常有用。
- 加入房间:
enter_room(sid, room_name) - 离开房间:
leave_room(sid, room_name) - 向房间广播:
emit('event_name', data, room=room_name)
命名空间
在同一个 Socket.IO 连接上创建多个独立的通信通道,这允许你将不同类型的逻辑(聊天和通知)分离到不同的命名空间下,避免事件名称冲突。
默认的命名空间是 ,你可以通过 namespace='/chat' 这样的方式指定。
快速入门:一个简单的 "Hello, World" 示例
这个例子将展示一个独立的服务器和一个独立的客户端。

服务器端代码 (server.py)
import socketio
# 创建一个 Socket.IO 服务器实例
# async_mode 可以是 'threading', 'eventlet', 'gevent', 'asyncio'
# 对于简单的脚本,'threading' 或 'asyncio' 是好选择
sio = socketio.Server(async_mode='threading')
# 处理 'connect' 事件
@sio.event
def connect(sid, environ):
print(f"客户端 {sid} 已连接")
# 连接成功后,向客户端发送一个 'welcome' 事件
sio.emit('welcome', {'data': '欢迎连接到 Socket.IO 服务器!'}, to=sid)
# 处理 'message' 事件
@sio.event
def message(sid, data):
print(f"从客户端 {sid} 收到消息: {data}")
# 收到消息后,将消息回显给发送者
sio.emit('message_response', {'data': f'服务器收到了你的消息: {data}'}, to=sid)
# 处理 'disconnect' 事件
@sio.event
def disconnect(sid):
print(f"客户端 {sid} 已断开连接")
# 创建一个 ASGI 应用,用于 WSGI 服务器(如 eventlet, gevent)或 ASGI 服务器
app = socketio.WSGIApp(sio)
if __name__ == '__main__':
# 使用 eventlet 作为 WSGI 服务器来运行
# 你需要先安装 eventlet: pip install eventlet
import eventlet
eventlet.wsgi.server(eventlet.listen(('', 5000)), app)
# 或者使用简单的 Flask 内置服务器 (仅用于开发,不推荐生产环境)
# from flask import Flask
# app = Flask(__name__)
# app = socketio.WSGIApp(sio, app)
# app.run(host='0.0.0.0', port=5000)
客户端代码 (client.py)
import socketio
import time
# 创建一个 Socket.IO 客户端实例
sio = socketio.Client()
# 定义事件处理函数
@sio.event
def connect():
print("成功连接到服务器!")
# 连接后,发送一个 'message' 事件
sio.emit('message', {'data': '你好,服务器!'})
@sio.event
def welcome(data):
print(f"收到欢迎消息: {data}")
@sio.event
def message_response(data):
print(f"收到服务器响应: {data}")
@sio.event
def disconnect():
print("与服务器断开连接")
# 连接到服务器
# 如果服务器和客户端在同一台机器上,host 是 'localhost'
try:
sio.connect('http://localhost:5000')
print(f"我的连接 ID 是: {sio.sid}")
# 保持脚本运行,以便接收消息
sio.wait()
except Exception as e:
print(f"连接失败: {e}")
如何运行:
- 安装依赖:
pip install python-socketio eventlet
- 启动服务器:
python server.py
你会看到
客户端 <sid> 已连接的输出。 - 启动客户端:
python client.py
客户端会连接到服务器,并打印出欢迎消息和服务器响应,服务器端也会打印出接收到的消息。
服务器端 编程
创建服务器
如上所示,核心是 socketio.Server,你需要选择一个 async_mode:
'threading': 使用线程池,简单,但不是最高效的。'eventlet': 性能最好,推荐用于生产环境,需要安装eventlet。'gevent': 另一个高性能选择,需要安装gevent。'asyncio': 使用 Python 原生的asyncio库,适合异步应用。
事件处理
使用 @sio.event 装饰器来定义事件处理函数。
@sio.event
def my_custom_event(sid, data):
print(f"收到自定义事件,数据: {data}")
# 处理逻辑...
发送事件
emit(event_name, data, to=sid): 发送给特定客户端。emit(event_name, data, room=room_name): 发送给房间内所有客户端。emit(event_name, data, skip_sid=sid): 广播给所有客户端,除了指定的sid。send(data, to=sid):emit的别名,用于发送数据而不指定事件名(默认为 'message')。
房间管理
房间操作必须在事件处理函数内部进行,因为需要客户端的 sid。
@sio.event
def join_chat(sid, data):
# data 可以包含房间名,{'room': 'general'}
room = data.get('room', 'default')
sio.enter_room(sid, room)
sio.emit('joined', {'message': f'你已加入房间 {room}'}, to=sid)
sio.emit('user_joined', {'message': f'一个用户加入了房间 {room}'}, room=room, skip_sid=sid)
@sio.event
def leave_chat(sid, data):
room = data.get('room', 'default')
sio.leave_room(sid, room)
sio.emit('left', {'message': f'你已离开房间 {room}'}, to=sid)
sio.emit('user_left', {'message': f'一个用户离开了房间 {room}'}, room=room, skip_sid=sid)
异步事件处理 (使用 asyncio)
如果你选择 async_mode='asyncio',你的事件处理函数可以是 async 函数。
import asyncio
sio = socketio.Server(async_mode='asyncio')
@sio.event
async def async_message(sid, data):
print(f"收到异步消息: {data}")
# 模拟一个耗时操作
await asyncio.sleep(1)
sio.emit('async_response', {'data': '异步操作完成!'}, to=sid)
客户端 编程
客户端逻辑相对简单。
创建客户端和连接
socketio.Client() 创建客户端实例,connect() 方法建立连接。
sio = socketio.Client()
sio.connect('http://your-server.com')
发送和接收事件
同样使用 emit 和 @sio.event。
@sio.event
def connect():
print("连接成功!")
sio.emit('get_status')
@sio.event
def status(data):
print(f"服务器状态: {data}")
@sio.event
def disconnect():
print("连接断开")
# 在主线程中保持运行
sio.wait()
与 Web 框架集成
在生产环境中,Socket.IO 服务器通常与一个 Web 框架集成。
Flask 集成 (Flask-SocketIO)
Flask-SocketIO 是最流行的集成方式。
from flask import Flask
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
socketio = SocketIO(app, async_mode='eventlet') # 使用 eventlet 获得最佳性能
@app.route('/')
def index():
return "Flask-SocketIO 服务器运行中"
@socketio.on('my_event')
def handle_my_custom_event(json):
print('收到 json: ' + str(json))
# 回复给发送者
emit('my_response', json, json=True)
# 广播给所有客户端(包括发送者)
# emit('my_response', json, broadcast=True, json=True)
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=5000)
Django 集成
对于 Django,推荐使用 channels 和 channels-socketio (或 daphne 作为 ASGI 服务器)。
FastAPI 集成
FastAPI 原生支持 ASGI,与 python-socketio 的 async_mode='asyncio' 结合得很好。
from fastapi import FastAPI
import socketio
app = FastAPI()
# 创建一个 ASGI 兼容的 Socket.IO 服务器
sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins='*')
# 将 Socket.IO 应用包装成一个 ASGI 应用
socketio_app = socketio.ASGIApp(socketio=sio)
# 将 ASGI 应用挂载到 FastAPI 的一个路径上
app.mount('/socket.io', socketio_app)
@sio.event
async def connect(sid, environ):
print(f"客户端 {sid} 连接")
await sio.emit('message', {'msg': '连接成功'}, to=sid)
@sio.event
async def my_message(sid, data):
print(f"从 {sid} 收到消息: {data}")
await sio.emit('message', {'msg': data['msg']}, room=sid)
# 你的 FastAPI 路由
@app.get("/")
async def read_root():
return {"message": "FastAPI with Socket.IO"}
高级特性
认证
你可以在连接时或事件中验证客户端身份,一种常见做法是在 connect 事件中检查 HTTP 请求头中的认证信息。
@sio.event
def connect(sid, environ):
# environ 是一个类似 WSGI environ 的字典,包含请求信息
# 从查询参数获取 token
token = environ.get('QUERY_STRING', '').split('token=')[-1]
if not is_valid_token(token):
print(f"客户端 {sid} 认证失败")
# 拒绝连接
return False
print(f"客户端 {sid} 认证成功")
sio.enter_room(sid, 'authenticated_users')
return True
def is_valid_token(token):
# 你的验证逻辑
return token == 'secret-token'
自定义传输器
你可以配置底层传输方式,但通常默认的自动选择已经足够。
跨域资源共享
如果你的前端和后端不在同一个域名下,需要配置 CORS。
- 对于
Flask-SocketIO,在初始化时设置cors_allowed_origins。 - 对于独立服务器,可以使用
socketio.CORSConfig或中间件。
常见问题与最佳实践
-
Q: 如何处理大量并发连接?
- A: 使用
async_mode='eventlet'或async_mode='gevent',它们使用事件循环,可以高效处理数千个并发连接,避免使用threading模式。
- A: 使用
-
Q: 如何确保消息不丢失?
A: Socket.IO 本身在连接断开时会尝试将消息排队并在重连后发送,但对于关键业务逻辑,通常需要实现自己的持久化消息队列(如 Redis)。
-
Q:
sid是什么?- A:
sid(Session ID) 是服务器为每个客户端连接生成的唯一标识符,用于在服务器端精确地定位和操作某个客户端。
- A:
-
最佳实践:
- 使用房间进行广播:除非必要,否则不要使用
broadcast=True,优先使用房间,这样可以精确控制消息的接收者。 - 保持事件处理函数简洁:事件处理函数应尽可能快地完成,避免阻塞,对于耗时操作(如数据库查询、API 调用),使用异步(
async/await)或将其放到后台任务队列中。 - 错误处理:在客户端和服务器端都添加适当的
try...except块来处理网络异常和逻辑错误。 - 阅读官方文档:
python-socketio的官方文档是最权威的参考资料,链接在此。
- 使用房间进行广播:除非必要,否则不要使用
