news 2026/10/1 8:06:36

Chatto Realtime实时协议v4详解:WebSocket+Protobuf的快照、事件与断线恢复

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Chatto Realtime实时协议v4详解:WebSocket+Protobuf的快照、事件与断线恢复

Chatto Realtime实时协议v4详解:WebSocket+Protobuf的快照、事件与断线恢复

【免费下载链接】chattoA fully-featured team and group chat application that you can easily selfhost.项目地址: https://gitcode.com/gh_mirrors/chatt/chatto

Chatto 是一个可自托管的全功能团队与群组聊天应用,其 Realtime 实时协议 v4 使用 WebSocket 传输 Protobuf 二进制帧,通过"精确快照 + 语义事件 + 15分钟断线恢复游标"三件套,让消息、反应、房间变更等在毫秒级送达所有在线客户端。本文将从零讲透这套实时协议的工作机制。

Chatto 是什么?一个单二进制自托管聊天服务器

Chatto 用单个 Go 二进制嵌入 NATS JetStream 作为数据底座,前端是 SvelteKit SPA,开箱即用地提供频道、私信、线程、语音通话、文件附件与机器人生态。

实时能力是聊天应用的灵魂:别人发的消息"立刻"出现、在线状态即时点亮,背后正是 realtime.proto 定义的实时协议在支撑。

为什么实时层选择二进制 WebSocket + Protobuf?

很多聊天产品用 JSON 文本帧,而 Chatto 的实时端点GET /api/realtime走的是纯二进制 Protobuf 帧,带来三个好处:

  • 📦体积小:紧凑的 varint 编码比 JSON 文本节省大量带宽,对高频事件流尤其明显;
  • 🧬可演进:Protobuf 字段号天然支持增量添加新字段,客户端遇到不认识的新事件可以安全跳过;
  • 🔒不泄露内部结构:公开事件使用独立的事件目录,内部存储字段永远不会出现在公开帧中。

一个容易混淆的细节:protobuf 包名是chatto.realtime.v1,这里的 v1 只是 schema 命名空间;行为协议版本是 4,且 v4 是服务器唯一接受的手shake版本。

协议 v4 的 5 种帧:一条连接完整生命周期

整个协议异常简洁:客户端只发一条消息,之后永远只接收。

帧类型方向作用
RealtimeSubscribe客户端 → 服务器首帧:声明协议版本 4、凭据、断线恢复游标、回退策略
snapshot服务器 → 客户端当前时刻的精确授权内容快照(至多一次)
event服务器 → 客户端授权后的语义事件(消息、反应、房间变更……)
caught_up服务器 → 客户端标记"追赶完成",附交接游标,此后进入纯直播
heartbeat/close服务器 → 客户端存活探测 / 带重连指引的关闭指令

完整定义见 RealtimeServerFrame。

快照(Snapshot):一次性拿到"当前状态"

冷启动或断线超过恢复窗口时,服务器会先发一个原子快照帧,内容都是"此刻的权威状态":

  • 服务器公开资料、你可见的全部房间目录与分组布局
  • 正在进行的语音通话
  • 快照资源引用到的用户资料

⚠️ 快照有意保持有界:消息历史、搜索结果、文件列表等大数据集不在其中,客户端按需通过 ConnectRPC 拉取。且规则很严格——如果在caught_up到达前连接断了,快照必须整体丢弃,避免半个快照污染本地状态。

语义事件(Events):所有客户端共享的公开事件目录

RealtimeEvent的 oneof 联合就是公开事件目录,涵盖message_posted、reaction_added、room_created、voice_call_started、user_typing等几十个变体,定义在 events.proto 中。

例如上图中用户发送照片后,服务器完成图片处理时会向房间内每个客户端推送asset_processing_succeeded事件,消息行里的图片随之立即可见——无需轮询。

几个对新手很关键的设计:

  • 🎯事件携带游标的属于"持久事件"(消息、反应、成员变更),可重放恢复;不带游标的(正在输入、在线状态)只是"直播信号",错过就错过;
  • ⚡message_posted事件直接携带明文正文(body_plaintext),客户端可先显示临时消息行,再异步补全附件、反应等详情;
  • 🛡️新增事件变体可安全忽略:事件游标放在 oneof 之外,老客户端遇到不认识的新事件照常推进游标,无需升级。

断线恢复:15 分钟游标 + 三条安全回退路径

这是 v4 最精巧的部分。每个事件和心跳都携带一个不透明恢复游标(opaque resume cursor):

  1. 它是一个经认证加密的短令牌,15 分钟过期,绑定到具体用户与订阅范围;
  2. 短暂掉线重连时,客户端把最后安全保存的游标放进RealtimeSubscribe.resume_cursor;
  3. 服务器重放游标之后的授权事件,随后发caught_up告诉你实际走了哪条路径:
recovery结果含义
RESUMED✅ 游标有效,已补齐间隙事件(哪怕零条也算)
SNAPSHOT🔄 游标失效,已下发全新精确快照
LIVE_ONLY📡 直接从当前边界开始,不发任何历史

为防止重放拖垮服务器,追赶过程有严格上限:最多扫描 10,000 条事件序列、最多下发 2,000 条事件、30 秒总时限,超限自动走你声明的回退路径,绝不"半截重放"。

当连接必须终止时,close帧会给出机器可读的关闭码(如SESSION_RENEWAL_REQUIRED需要续期会话、RESYNC_REQUIRED需丢弃游标重新同步)以及建议的重试延迟,客户端据此自动重连。

设计哲学:快照是"现在是什么",事件是"发生了什么"

记住这句话就理解了 v4 的骨架:

快照陈述当前状态,事件陈述领域变更,二者各司其职、复用同一套公开资源消息。

而命令、分页、历史消息等"主动读取"仍由 ConnectRPC 承担——实时流从不变成无界的资源转储。前端、机器人、第三方客户端(如 chatto-client 集成包)共享同一套事件词汇,这正是 ADR-091 的核心决策。

延伸阅读:文档与源码路径

  • 协议定义:realtime.proto(帧与握手)、events.proto(事件目录)
  • 功能设计:FDR-045 实时事件流
  • 架构决策:ADR-091、ADR-093 公开事件联合、ADR-094
  • 架构清单:realtime-delivery.md
  • 服务端实现:realtime.go;前端传输层:realtimeTransport.svelte.ts

小结

Chatto Realtime 协议 v4 用一条 WebSocket 连接、五种服务器帧,把"状态同步 + 变更推送 + 断线恢复"三件事讲得清清楚楚:快照负责冷启动,游标负责短间隙恢复,caught_up帧明确告知你此刻处于直播边界。无论你是自托管管理员、机器人开发者还是协议研究者,这套协议都值得细细品味。

【免费下载链接】chattoA fully-featured team and group chat application that you can easily selfhost.项目地址: https://gitcode.com/gh_mirrors/chatt/chatto

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 8:05:17

知行之桥 MaBang 端口使用指南——Get Inventory 库存获取篇

一、功能背景 MaBang(马帮 ERP)端口可以连接马帮 ERP,实现订单创建和 SKU 库存查询。 MaBang 端口目前支持两种 API 模式: API 模式数据方向作用Create Order工作流 → 马帮 ERP将订单 JSON 提交至马帮,并检查订单创…

作者头像 李华
网站建设 2026/10/1 8:04:13

NVIDIA OpenShell 入门:为自主 AI Agent 配置沙箱与访问策略

NVIDIA/OpenShell 是一个面向自主 AI Agent 的开源运行时。它不负责替换模型,而是为 Agent 提供隔离沙箱、文件与系统调用限制、网络访问控制,以及按获准端点注入凭据的机制。 主要能力 OpenShell README 当前强调两类能力: 内核层运行时…

作者头像 李华