玄武屏多端联动基于 WebSocket 长连接。本节讲同步机制原理 + 断线重连策略。
协议层
客户端 ←→ Nuxt Server ←→ Redis Pub/Sub ←→ 其它客户端
↑
WebSocket gateway每个房间在 Redis 里有独立 channel,主讲人发的消息广播给该 channel 所有订阅者。
同步事件类型
| 事件 | 触发 | 内容 |
|---|---|---|
| page-change | 主讲人翻页 | { fromPage, toPage } |
| animation-step | 主讲人触发动画 | { page, order } |
| interaction | 主讲人点元素 | { elementId, action } |
| laser-pen | 主讲人激光笔 | { x, y } |
| black-screen | 主讲人按 B | { on } |
| task-publish | 主讲人发任务 | { task, options } |
| task-result | 参与者提交 | { studentId, answer } |
| reaction | 参与者反应 | { type: '👍 ✋ ❓' } |
心跳机制
- 客户端每 30s 发送 ping
- 服务端 60s 内未收到 ping → 标记离线
- 60s 后重连成功 → 自动恢复
- 60s 后未重连 → 视为永久离线,从参与者列表移除
断线重连策略
短暂断线(< 30s)
- 客户端检测到 WebSocket 关闭
- 立即尝试重连(指数退避:1s → 2s → 4s → 8s)
- 重连成功 → 同步到当前页(不会落后)
- 用户基本无感
中等断线(30s – 5min)
- 显示橙色"网络中断中..."提示
- 后台持续重试
- 重连后弹"已恢复"
- 期间错过的事件不重放(直接同步到最新状态)
长时间断线(> 5min)
- 显示红色"已离线"
- 页面变灰
- 用户可点"重新加入"手动恢复
同步策略:状态机 vs 事件流
玄武屏用状态机同步而非事件流:
状态机:客户端持有"当前应在第 5 页 order=3"的状态
事件流:每个动作都广播给客户端,客户端按序回放为什么选状态机:
- 断线后只需同步当前状态,不需要补播事件
- 服务端无需保存全量事件历史
- 网络抖动时不会乱序
延迟与抖动
| 延迟 | 体验 |
|---|---|
| < 50ms | 完美同步 |
| 50–100ms | 几乎察觉不到 |
| 100–200ms | 偶尔感觉到 |
| 200–500ms | 明显延迟,但可用 |
| > 500ms | 体验差,建议改善网络 |
实测:国内城域网平均 30–80ms,跨城 100–200ms,跨国 200–600ms。
参与者本地操作不广播
一个常见问题:"学生拖动 GGB 滑块,老师能看到吗?"
默认看不到。学生的本地操作只在自己屏幕生效,不广播给其他人。
要让老师看到,有两种途径:
- 截图同步:老师定时拉学生屏幕截图(轮询)
- 变量同步:动画作者预埋的变量上报(推送)
详见「38. 课堂互动系统总览」。
多区域部署
跨地域大型课堂(如国际混合课):
- 主网关在中国,海外学生延迟 > 300ms
- 解决:部署边缘网关(CN / SEA / EU / NA)
- 同房间的客户端连最近网关,跨网关 Redis Pub/Sub 同步
部署细节联系「77. 定制服务」。
网络故障应急
如果 WebSocket 完全连不上:
- 自动降级 HTTP 长轮询(5s 间隔)
- 性能差但可用
- 适合极差网络(车载、远洋、深山)
调试
「设置 → 网络」面板:
- 当前延迟
- 丢包率
- 重连次数
- WebSocket 状态
推送通知
老师可对单个学生发推送:
- "请翻到第 8 页参与练习"
- "你的答题超时了"
- "课程结束,可以离开了"
通过 Redis Pub/Sub 单点发送。
下一节讲多终端矩阵适配。
