基于 SocketIO 消息协议规范,并构建FastAPI上的SocketIO 应用
最近在研究Python下整合FastAPI的Socket.IO 应用,对于其WebSocket的消息报文协议进行了深入了解,并整理了相关的协议内容,整合到FastAPI的WebSocket通讯处理中,用作多端的消息通讯,如聊天,系统信息通知等。
1. 总体设计
- 统一事件名:客户端和服务端只监听/发送一个事件,例如:"message"。
- 消息类型区分:通过 msgtype 字段区分不同的业务逻辑。
- 通用字段:每条消息都必须包含的基础字段(如 msgtype, sender, timestamp)。
- 扩展字段:放在 payload 里,根据不同类型自由定义。
- 报文格式:统一为 JSON 格式。
- 广播机制:服务端可以广播消息到所有客户端,方便消息的实时推送。
- 房间机制:服务端可以创建、加入或离开房间,方便消息的分发。
2. 消息格式
{
"msgtype": "string", // 消息类型,如 "chat", "notification", "command"
"sender": "string", // 发送者标识,如用户ID或系统标识
"timestamp": "number", // 消息发送时间戳(毫秒)
"payload": { // 消息内容(不同 msgtype 有不同格式)
// 根据 msgtype 定义不同的结构
},
"room": "string", // 房间标识(可选),表示消息所属的房间
"touser": "string", // 接收者标识(可选),表示消息的目标用户,多个接收者用‘|’分隔
"totag": "string", // 接收者标签(可选),表示消息的目标用户标签,多个标签用‘|’分隔
}
例子:
{
"msgtype": "chat",
"room": "room1",
"sender": "user1",
"timestamp": 1612345678901,
"payload": {
"text": "Hello, world!"
}
}
3. 消息类型
3.1 系统类消息(system)
系统类消息由系统发送,用于通知客户端或服务端状态变化。
{
"msgtype": "system_notice",
"sender": "system",
"timestamp": 1694412000000,
"payload": {
"level": "info", // info, warning, error
"text": "服务器即将维护"
}
}
3.2 聊天类消息(chat)
聊天类消息由用户发送,用于聊天。
{
"msgtype": "chat_message",
"room": null,
"sender": "alice",
"timestamp": 1694412000000,
"payload": {
"text": "你好,大家!",
"extra": {
"emoji": ""
}
}
}
3.3 房间操作类消息(room)
房间操作类消息用于创建、加入或离开房间。
{
"msgtype": "room_event",
"room": "room1",
"sender": "bob",
"timestamp": 1694412000000,
"payload": {
"action": "join", // join, leave, create, destroy
"user": "bob"
}
}
3.4 ACK / 状态反馈消息(ack)
ACK / 状态反馈消息用于确认客户端或服务端收到消息。
{
"msgtype": "ack",
"sender": "server",
"timestamp": 1694412000000,
"payload": {
"status": "ok", // ok, fail
"requestId": "abc123",
"msg": "消息已送达"
}
}
3.5 命令类消息(command)
命令类消息用于向服务端发送指令。
{
"msgtype": "command",
"sender": "user1",
"timestamp": 1694412000000,
"payload": {
"command": "create_room",
"args": {
"name": "room1"
}
}
}
3.6 图片类消息(image)
图片类消息用于发送图片。
{
"msgtype": "image",
"room": "room1",
"sender": "user1",
"timestamp": 1694412000000,
"payload": {
"url": "https://example.com/image.jpg"
}
}
3.7 文件类消息(file)
文件类消息用于发送文件。
{
"msgtype": "file",
"room": "room1",
"sender": "user1",
"timestamp": 1694412000000,
"payload": {
"url": "https://example.com/file.pdf"
}
}
3.8 语音类消息(voice)
3.9 视频类消息(video)
3.10 位置类消息(location)
3.11 其他类型消息(other)
3.12 自定义消息(custom)
4、Python 服务端示例
import time
import socketio
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
def make_message(msg_type, sender, payload, room=None):
return {
"msgtype": msg_type,
"room": room,
"sender": sender,
"timestamp": int(time.time() * 1000),
"payload": payload
}
@sio.event
async def chat_message(sid, data):
msg = make_message("chat_message", sid, {"text": data})
await sio.emit("message", msg) # 广播
@sio.event
async def join_room(sid, room):
sio.enter_room(sid, room)
msg = make_message("room_event", "system", {"action": "join", "user": sid}, room)
await sio.emit("message", msg, room=room)
5、Vue3 前端示例
socket.on("message", (msg) => {
switch (msg.msgtype) {
case "chat_message":
console.log(`[${msg.sender}] 说: ${msg.payload.text}`);
break;
case "system_notice":
console.log(`系统通知: ${msg.payload.text}`);
break;
case "room_event":
console.log(`房间 ${msg.room} 事件: ${msg.payload.action} -> ${msg.payload.user}`);
break;
case "ack":
console.log(`ACK: ${msg.payload.status} (${msg.payload.msg})`);
break;
default:
console.warn("未知消息类型:", msg);
}
});
6、通信流程示例
6.1 普通消息
- 客户端发送:
{
"msgtype": "chat_message",
"sender": "alice",
"timestamp": 1694412000000,
"payload": {
"text": "Hello World"
}
}
- 服务端广播:
{
"msgtype": "chat_message",
"sender": "alice",
"timestamp": 1694412000500,
"payload": {
"text": "Hello World"
}
}
6.2 房间消息
6.2.1 创建房间
- 客户端发送:
{
"msgtype": "command",
"sender": "bob",
"timestamp": 1694412000000,
"payload": {
"command": "create_room",
"args": {
"name": "room1"
}
}
}
2. 服务端响应:
```json
{
"msgtype": "ack",
"sender": "server",
"timestamp": 1694412000000,
"payload": {
"status": "ok",
"requestId": "abc123",
"msg": "房间 room1 创建成功"
}
}
6.2.2 加入房间
1.客户端发送:
{
"msgtype": "room_event",
"sender": "alice",
"timestamp": 1694412000000,
"payload": {
"action": "join",
"user": "alice"
}
}
2.服务端响应:
{
"msgtype": "ack",
"sender": "server",
"timestamp": 1694412000000,
"payload": {
"status": "ok",
"requestId": "abc123",
"msg": "用户 alice 加入房间 room1"
}
}
3.服务端广播:
{
"msgtype": "room_event",
"room": "room1",
"sender": "server",
"timestamp": 1694412000000,
"payload": {
"action": "join",
"user": "alice"
}
}
6.2.3 离开房间
1.客户端发送:
{
"msgtype": "room_event",
"sender": "alice",
"timestamp": 1694412000000,
"payload": {
"action": "leave",
"user": "alice"
}
}
2.服务端响应:
{
"msgtype": "ack",
"sender": "server",
"timestamp": 1694412000000,
"payload": {
"status": "ok",
"requestId": "abc123",
"msg": "用户 alice 离开房间 room1"
}
}
7、优点
统一事件名:客户端和服务端只监听/发送一个事件,降低耦合度,提高代码可读性。
消息类型区分:通过 msgtype 字段区分不同的业务逻辑,提高消息处理效率。
通用字段:每条消息都必须包含的基础字段(如 msgtype, sender, timestamp),方便服务端处理。
扩展字段:放在 payload 里,根据不同类型自由定义,方便消息内容的扩展。
状态反馈消息:ACK / 状态反馈消息用于确认客户端或服务端收到消息,方便客户端处理。
命令类消息:命令类消息用于向服务端发送指令,方便服务端处理。
广播机制:服务端可以广播消息到所有客户端,方便消息的实时推送。
房间机制:服务端可以创建、加入或离开房间,方便消息的分发。
扩展性:服务端和客户端可以自由扩展消息类型,增加更多的业务逻辑。
兼容性:服务端和客户端可以兼容 SocketIO 协议,方便与其他服务端和客户端通信。
易用性:服务端和客户端可以直接使用 SocketIO 库,降低学习成本。
性能:服务端和客户端可以利用 WebSocket 协议,提高消息传输效率。
8、关于 Socket.IO的挂载的注意事项
Socket.IO 是一个基于 WebSocket 的实时通信协议,它可以实现浏览器和服务器之间的双向通信。
Socket.IO 协议的实现主要依赖于两个部分:
- Socket.IO 服务器:Socket.IO 服务器负责维护连接,处理消息,并向客户端推送消息。
- Socket.IO 客户端:Socket.IO 客户端负责维护连接,向 Socket.IO 服务器发送消息,并接收消息。
如果你用 app = register_app(),然后用 uvicorn main:app 或者 config = uvicorn.Config(app, ...),这样启动的“app”是原生 FastAPI 实例,不包含 Socket.IO 的功能,所以前端 Socket.IO 客户端连接时不会触发 @sio.event 的回调!
解决方法:
你需要让 Uvicorn 启动的是 ASGI 的组合应用,即 sio_app,而不是纯 FastAPI 的 app。
import socketio
from fastapi import FastAPI
def register_app():
app = FastAPI()
# ...注册路由等...
return app
app = register_app()
sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins='*')
sio_app = socketio.ASGIApp(sio, other_asgi_app=app)
# main.py 入口
if __name__ == "__main__":
import uvicorn
# 下面两种写法都可以
uvicorn.run(sio_app, host="0.0.0.0", port=8000)
# 或
# config = uvicorn.Config(sio_app, host="0.0.0.0", port=8000)
# server = uvicorn.Server(config)
# server.run()
注意:一定要启动的是 sio_app,不是 app!
你可以继续用 register_app() 组织你的 FastAPI 配置,但最终给 Uvicorn 的必须是 sio_app。
最后我们来看看再FastAPI项目上对接的例子通讯截图(尚未完工,持续改进优化中)。
服务端的信息截图

客户端信息截图

基于 SocketIO 消息协议规范,并构建FastAPI上的SocketIO 应用的更多相关文章
- 即插即用,基于阿里云Ganos快速构建云上开源GIS方案
对于轻量级GIS应用,选择具备时空能力的云上数据库再搭配开源GIS软件,能够快速构建稳定.廉价.实用的GIS解决方案.Ganos是阿里云自研时空基础设施(PaaS层)的核心引擎,该引擎整合了云上异构计 ...
- 物联网网关开发:基于MQTT消息总线的设计过程(上)
道哥的第 021 篇原创 目录 一.前言 二.网关的作用 2.1 指令转发 2.2 外网通信 2.3 协议转换 2.4 设备管理 2.5 边沿计算(自动化控制) 三.网关内部进程之间的通信 3.1 网 ...
- .Net Core with 微服务 - 使用 AgileDT 快速实现基于可靠消息的分布式事务
前面对于分布式事务也讲了好几篇了(可靠消息最终一致性 分布式事务 - TCC 分布式事务 - 2PC.3PC),但是还没有实战过.那么本篇我们就来演示下如何在 .NET 环境下实现一个基于可靠消息的分 ...
- 码途有道----基于系统观的核心能力构建-by-韩宏老师
原文链接:http://blog.sina.com.cn/s/blog_7d5a09f90102v341.html 有感于同学们在大学中如何学习计算机技术有些感概,将我书(老码识途)中的序言整理了一下 ...
- AngularJS是为了克服HTML在构建应用上的不足而设计的
AngularJS中文网:http://www.apjs.net/ 简介 AngularJS是为了克服HTML在构建应用上的不足而设计的.HTML是一门很好的为静态文本展示设计的声明式语言,但要构 ...
- 基于Kafka消息驱动最终一致事务(一)
基本可用软状态最终一致事务 本用例分两个数据库分别是用户库和交易库,不使用分布式事务,使用基于消息驱动实现基本可用软状态最终一致事务(BASE).现在说明下事务逻辑演化步骤,尊从CAP原则,即分布式系 ...
- 如何基于 K8S 多租能力构建 Serverless Container
当前 Kubernetes 已经成为名副其实的企业级容器编排规范,很多云平台都开始提供兼容 Kubernetes 接口的容器服务.而在多用户支持方面,多数平台选择直接提供专属虚机集群,用户需要花费大量 ...
- 基于jersey和Apache Tomcat构建Restful Web服务(二)
基于jersey和Apache Tomcat构建Restful Web服务(二) 上篇博客介绍了REST以及Jersey并使用其搭建了一个简单的“Hello World”,那么本次呢,再来点有趣的东西 ...
- 基于rabbitMQ 消息延时队列方案 模拟电商超时未支付订单处理场景
前言 传统处理超时订单 采取定时任务轮训数据库订单,并且批量处理.其弊端也是显而易见的:对服务器.数据库性会有很大的要求,并且当处理大量订单起来会很力不从心,而且实时性也不是特别好 当然传统的手法还可 ...
- 基于Redis消息的订阅发布应用场景
目录 基于Redis消息的订阅发布应用场景 1.应用背景 2.困境 2.1 锁表风险 2.2 实时性差 2.3 增加编程复杂性 2.4 实时效果 3.解决方案 3.1 前端传值给服务端 3.2 服务端 ...
随机推荐
- java----IO字节流读写文件
IO流 IO流分类 如果是按照数据的流向划分: 输入流 输出流 判断输入还是输出流 以当前程序做参照物,观察数据是流入还是流出,如果流出,则使用输出流,如果数据是流入,则使用输入流. 如果按照处理的单 ...
- docusaurus简单使用
前言 docusaurus是一款使用markdown编写手册文档的工具,同类竞品有vitePress (放弃不维护的vuepress吧) 目前来看,比后者多了10k个start. docusaurus ...
- 企业微信公众号本地调试auto2.0
适配开发者工具 企业微信公众号.微信公众号本质相同,因为我在开发企业号,所以拿企业号为例 首先添加企业应用 然后进入改应用,配置主页.网页授权及JS-SDK.企业微信授权登录 注意企业微信不允许配置l ...
- 前端开发系列120-进阶篇之deepClone
本文讨论数据的拷贝,并给出深拷贝的实现代码. 拷贝即复制( copy | clone ),获取指定数据副本的一种行为,理论上我们可以对任意类型的数据进行拷贝,包括但不限于null.undefined. ...
- java 中 sleep & wait 的区别
简介 简单来说 一个和线程同步有关, 一个单纯的线程延迟等待. 1.sleep是线程中的方法,但是wait是Object中的方法. 2.sleep方法不会释放lock,但是wait会释放,而且会加入到 ...
- fowsniff WP
下载地址: https://download.vulnhub.com/fowsniff/Fowsniff_CTF_ova.7z category:重要 awk剪切得到字典,巩固awk使用技巧 motd ...
- RestCloud ETL实践之无标识位实现增量数据同步
步骤1: 从平台首页进入数据源管理 步骤2: 新建数据源 步骤3:选择需要连接的数据源类型 步骤4:填写数据源相关配置 步骤5: 测试连接数据库 步骤6: 从平台首页进入数据集成开发模块 步骤7: 新 ...
- ICEE-RF Trisistors-
Radio frequency (RF) transistors RF Transistor subcategories Low Noise RF Transistors High Linearity ...
- Rust中的匿名函数与闭包
一.匿名函数 语法:"|参数名| 语句" 参考下面的这个示例: fn add(a: i32, b: i32) -> i32 { a + b } fn main() { let ...
- unity代码编译时间分析工具
https://github.com/needle-tools/compilation-visualizer 工具2 Editor Iteration Profiler (EIP) 地址: https ...