2. CoAP协议核心回顾
Observe 扩展并不是一套独立协议,它建立在 CoAP 已有的请求/响应模型、消息层语义、Token 匹配机制以及选项与载荷结构之上。要理解“服务器如何主动把资源状态推给客户端”,必须先看清 CoAP 原本如何完成一次普通交互,以及哪些字段在 Observe 中被复用、扩展或重新解释。本节围绕 RFC 7252 定义的 CoAP 基础机制展开,为后续 Observe 选项、通知序列与重注册逻辑建立准确的协议坐标。
一、请求/响应模型:从客户端发起到服务器应答
CoAP 采用类 HTTP 的请求/响应语义,但运行在 UDP 之上,因此把“可靠性”拆分为消息层与请求/响应层两个层次。客户端发送一个请求消息,其中包含方法码(GET、POST、PUT、DELETE)、请求 URI、可选 Token 以及若干选项;服务器返回响应消息,包含响应码(如 2.05 Content、4.04 Not Found)和可选载荷。请求与响应通过 Token 关联,而不是通过传输层连接关联。
CoAP 的 URI 由选项分段表达:Uri-Host、Uri-Port、Uri-Path、Uri-Query。例如请求 coap://sensor.local:5683/temp/room1?unit=c 时,Uri-Path 选项依次为 temp、room1,Uri-Query 为 unit=c。这种“选项即 URI 分量”的设计使 CoAP 报文紧凑,也意味着 Observe 只需新增一个选项即可表达“订阅”语义,而不必改变请求/响应骨架。
二、消息类型:CON、NON、ACK、RST
CoAP 消息层定义了四种消息类型,它们决定了一次交互是否需要确认、如何复用报文以及如何拒绝异常消息:
- CON(Confirmable,可确认):接收方必须回复 ACK 或 RST。发送方若未在超时前收到应答,会按指数退避重传。适合需要可靠送达的请求或通知。
- NON(Non-confirmable,不可确认):不要求确认,适合周期性、可容忍丢失的数据,如高频传感器读数。
- ACK(Acknowledgment,确认):对 CON 消息的确认,可携带响应(piggybacked response),也可为空 ACK 表示“已收到,响应稍后单独发送”。
- RST(Reset,复位):表示收到无法处理或不需要的消息,例如 Token 不匹配、上下文缺失。RST 是 Observe 中取消订阅或拒绝通知的重要信号。
需要特别区分:消息类型属于消息层,请求/响应码属于请求/响应层。一个 CON 消息可以携带 GET 请求,也可以携带 2.05 响应;一个 NON 消息同样可以承载响应。Observe 通知既可以用 CON 发送以保证可靠,也可以用 NON 发送以降低开销,选择取决于资源变化频率与网络条件。
三、Token机制:请求与响应的匹配纽带
Token 是 0~8 字节的任意值,由客户端在请求中生成,服务器必须在对应响应中原样回填。客户端据此把响应匹配到尚未完成的请求。由于 UDP 无连接,同一客户端可能同时向同一服务器发起多个请求,Token 是区分它们的唯一手段。
在 Observe 场景中,Token 的作用被进一步放大:服务器发出的每一个通知都必须携带与初始订阅请求相同的 Token,客户端才能识别“这是同一个订阅的后续通知”。如果客户端收到一个 Token 未知的通知,应回复 RST,服务器据此移除该观察关系。因此,Token 不仅是请求匹配键,也是观察关系的隐式标识。
四、选项与载荷:可扩展的报文结构
CoAP 选项采用“增量编码”,每个选项由增量(Delta)、长度(Length)和值(Value)组成,按选项编号升序排列。选项分为 Critical/Elective 与 Unsafe/Safe-to-Forward 两类属性,接收方对不认识的 Critical 选项必须拒绝,对 Elective 选项可以忽略。这一机制保证了协议可扩展性:Observe 选项编号为 6,属于 Elective,因此不支持 Observe 的服务器可以忽略它并正常返回当前状态,而不会导致请求失败。
载荷(Payload)位于选项之后,由 0xFF 标记分隔,可承载任意字节序列。CoAP 不规定载荷格式,实际工程中常用 CBOR、JSON、SenML 或纯文本。对于 Observe,载荷就是每次通知携带的资源状态表示,其内容与普通 GET 响应完全一致,因此客户端可以用同一套解析逻辑处理首次响应和后续通知。
五、从基础机制到 Observe 的衔接点
把上述四部分放在一起,可以清楚看到 Observe 的接入方式:客户端在普通 GET 请求中增加 Observe 选项(值 0 表示注册),服务器在响应中回填 Observe 选项(携带序号),此后每次资源变化都用相同 Token 发送通知。消息类型仍由服务器按需选择 CON 或 NON;客户端若不再需要通知,可以发送 RST,或重新发送带 Observe=1 的 GET 请求来取消。
下面给出一个便于对照的字段速查表,用于在实现或抓包分析时快速定位关键字段:
| 字段/机制 | 作用 | Observe 中的变化 |
|---|---|---|
| Code(方法/响应码) | 表达请求方法与响应结果 | 注册与取消均使用 GET;通知使用 2.05 Content |
| Type(CON/NON/ACK/RST) | 决定可靠性与确认方式 | 通知可选 CON 或 NON;RST 用于取消或拒绝 |
| Token | 匹配请求与响应 | 同一订阅的所有通知复用同一 Token |
| Observe 选项(6) | 基础 CoAP 中不存在 | 0=注册,1=取消,响应中携带递增序号 |
| Payload | 承载资源表示 | 每次通知携带最新状态,格式与普通响应一致 |
理解这些基础机制后,后续讨论 Observe 的通知序号、重注册、资源状态一致性以及代理缓存行为时,都可以回到同一个判断框架:消息层决定“怎么送达”,请求/响应层决定“表达了什么”,Token 决定“属于哪次交互”,选项决定“扩展了什么语义”,载荷决定“状态是什么”。这五条线索贯穿 CoAP 与 Observe 的整个工程实现。