主题
7.2 订阅与推送机制
7.2.1 完整流程
- 客户端按当前页面协议建立 WebSocket 连接到
/ws(握手阶段不做认证) - 客户端发送
cmd: "subscribe"报文,带账号密码、项目名和数据点名数组 - 服务器校验账号后登记订阅关系
- 被订阅的数据点值发生变化时,服务器把变化打包成数组推送过来
- 连接断开时订阅关系失效,重连后必须重新发送订阅报文
7.2.2 报文格式
订阅(字段名是 cmd 和 datas):
json
{
"cmd": "subscribe",
"username": "linpan",
"password": "你的密码",
"project": "main",
"datas": ["车间1/1号机/温度", "车间1/1号机/湿度"]
}推送(JSON 数组,元素为 {name, value}):
json
[
{ "name": "车间1/1号机/温度", "value": "25.6" }
]修改订阅列表:没有单独的 unsubscribe 操作,直接重发一条完整的 subscribe 报文覆盖即可。
7.2.3 推送的触发条件
只有值真的变了才推送。同一个值反复写入不会产生推送,所以:
- 不要靠推送频率判断设备是否在线,用
server/online/...状态点判断 - 需要「即使不变也定时留一条」的记录,靠存盘方式实现(见 4.4 历史数据接口),不要靠 WebSocket
7.2.4 断线与降级
WebSocket 断开后要做两件事:
- 重连:建议用指数退避(1s、2s、4s…上限 30s),避免服务器重启时所有客户端同时冲击
- 重新订阅:重连成功后必须重发
subscribe,订阅关系不会自动恢复
云组态前端的做法可以直接参考:WebSocket 掉线后自动退回 HTTP get_real 轮询保证数据不中断,WebSocket 恢复后再切回推送。对可靠性要求高的对接程序建议按此思路实现双通道。
7.2.5 写保护
界面上刚点了按钮把某个点写成 1,服务器可能马上推来一条还是旧值 0 的消息(因为写入和推送有时序差),造成按钮显示回退到旧状态。
处理方式是加写保护窗口:本地写入后的一段时间内(云组态用 2 秒)忽略服务器推送的该点旧值,窗口结束后再接受推送。对接程序含控制类界面时,这一步不可省略。
7.2.6 性能建议
- 只订阅当前页面/当前业务真正需要的点,不要一次订阅几千个
- 数据点名越长,推送报文越大,命名不要过度冗长
- 高频变化的点(毫秒级)不适合直接推到浏览器,建议在设备侧或服务器侧先降频