3. Observe扩展机制原理
CoAP 的基础交互模型是请求/响应:客户端发一次 GET,服务器回一次 2.05 Content,事务即结束。这种模型对“读一次当前值”足够,但对温度曲线、设备状态、告警标志这类会持续变化的数据,客户端只能靠反复轮询,既浪费带宽又增加时延。Observe 扩展(RFC 7641)在 CoAP 之上引入观察者模式,让客户端注册一次,服务器在资源状态变化时主动推送通知,从而把“拉”变成“推”。
观察者模式如何映射到 CoAP 报文
观察者模式有三个角色:观察者(Observer,即 CoAP 客户端)、被观察者(Observable,即服务器上的某个资源)、以及连接两者的订阅关系。CoAP 用两个机制承载它:一是请求中的 Observe 选项,二是响应中的 Observe 选项。前者表示“我要订阅”,后者表示“这是订阅确认或后续通知”。
Observe 选项编号为 0x06,属于 elective(可选)选项,可出现在请求和响应中。它的取值是一个不超过 3 字节的无符号整数,语义随出现位置不同而不同:
- 在 GET 请求中,Observe 取值为 0,表示客户端请求注册观察关系;取值为 1,表示客户端请求注销该观察关系。
- 在 2.05 Content 响应中,Observe 携带一个 24 位序列号,用于让客户端判断通知的新旧顺序。
- 在错误响应(如 4.04、4.05)中,Observe 选项不应出现,客户端据此判定注册失败。
因此,一个典型的注册请求形如:
CON GET /sensors/temp
Uri-Path: sensors
Uri-Path: temp
Observe: 0
Token: 0x1a2b
服务器若接受订阅,返回:
ACK 2.05 Content
Observe: 12
Token: 0x1a2b
Content-Format: application/json
Payload: {"t":23.5}
此后每当温度变化,服务器主动发送新的 2.05 Content,携带递增的 Observe 序列号,Token 与注册时一致,客户端据此把通知关联到对应资源。
通知与确认流程
Observe 的通知可以走 CON(可确认)或 NON(不可确认)两种消息类型,选择取决于可靠性需求与网络开销的权衡。
使用 CON 通知时,服务器发送 CON 消息,客户端必须回 ACK。若服务器在重传超时内未收到 ACK,会重传,直到达到最大重传次数后认为该观察关系失效。这种方式可靠,但每条通知都要一次往返确认,适合告警等关键数据。
使用 NON 通知时,服务器直接发送 NON 消息,客户端不回 ACK。开销小、时延低,但丢包后客户端不会立即知道,只能靠后续通知的序列号发现跳变。适合高频、可容忍偶发丢失的采样数据。
序列号是通知排序的核心。它是一个 24 位整数,回绕后从 0 重新开始。客户端收到通知时,用 RFC 7641 定义的比较规则判断新旧:若新序列号与旧序列号之差(按 24 位模运算)落在 (0, 2^23) 区间,则新通知更新;否则视为过期或重排,应丢弃。这样即使网络乱序,客户端也不会用旧数据覆盖新数据。
此外,客户端在收到通知后若发现资源已不再需要,可发送带 Observe:1 的 GET 注销;服务器也可因资源被删除、权限变更或内部错误,用不带 Observe 选项的响应终止观察关系。
观察关系的生命周期
观察关系不是永久连接,而是一个有明确状态迁移的过程。理解生命周期,才能正确处理超时、注销和异常。
生命周期大致分为四个阶段:注册、活跃、终止、清理。注册阶段客户端发 Observe:0,服务器返回带 Observe 序列号的 2.05 即建立成功。活跃阶段服务器按资源变化推送通知,客户端持续用序列号校验。终止可由任一方发起:客户端发 Observe:1 注销,或服务器返回不带 Observe 的响应。清理阶段双方释放 Token 与观察条目,避免资源泄漏。
需要特别注意的是,观察关系与底层传输绑定。若客户端与服务器之间使用 DTLS,观察关系随 DTLS 会话存在;会话关闭,观察关系即失效。在 NAT 环境中,长时间无通知可能导致 NAT 映射超时,因此服务器通常会设置一个最大通知间隔,即使资源无变化也发送一次“心跳”通知,维持映射与观察关系。
观察关系状态迁移图
下图把上述注册、通知、确认、注销与失效路径集中呈现,便于对照报文理解状态变化。
结合图示可以看到,注册与终止是两条对称的路径,而活跃阶段的核心是“通知—序列号校验—按需确认”的循环。工程实现中,客户端应维护一张观察表,键为 Token,值为资源路径、最近序列号、最近接收时间;服务器端则维护订阅者列表,并在资源变更时遍历列表推送。只有把生命周期管理做扎实,Observe 才能在低功耗、弱网环境下稳定工作。