4. CoAP协议基础与LwM2M消息映射
LwM2M 的轻量特性并非凭空而来,它建立在 CoAP(Constrained Application Protocol,受限应用协议)之上。理解 LwM2M 的设备注册、对象读写、属性上报,本质上就是理解“LwM2M 操作如何被翻译成一条条 CoAP 报文”。本节先拆解 CoAP 的四个核心要素——方法、消息类型、选项、响应码,再给出 LwM2M 操作到 CoAP 请求的映射规则,最后说明如何用抓包工具验证这套映射。
一、CoAP 的报文结构与四个核心要素
CoAP 运行在 UDP 之上,默认端口 5683,使用 DTLS 时端口为 5684。它的固定头部只有 4 字节,结构紧凑:版本号(Ver,固定为 1)、消息类型(T,2 bit)、Token 长度(TKL,4 bit)、请求/响应码(Code,8 bit)、消息 ID(Message ID,16 bit),其后跟随 Token、选项(Options)和负载(Payload)。负载前有一个 0xFF 字节作为分隔符,用于区分“选项结束”和“负载开始”。
方法(Method)决定对资源做什么操作,取值位于 Code 字段的高 3 bit:GET(0.01)、POST(0.02)、PUT(0.03)、DELETE(0.04)。GET 用于读取资源,PUT 用于整体替换或创建资源,POST 用于触发动作或部分更新,DELETE 用于删除资源实例。
消息类型(Type)体现 CoAP 的可靠性机制,共四种:CON(Confirmable,需确认)、NON(Non-confirmable,不需确认)、ACK(Acknowledgement,确认应答)、RST(Reset,复位)。CON 报文要求对端回 ACK;若对端无法处理,则回 RST。NON 用于可容忍丢失的周期上报,以降低功耗。
选项(Options)是 CoAP 的扩展机制,采用“增量编号 + 长度”编码。与 LwM2M 关系最密切的选项包括:Uri-Path(编号 11,可重复,用于拼接资源路径)、Content-Format(编号 12,标识负载格式,如 11542 表示 SenML+CBOR、0 表示 text/plain)、Accept(编号 17,声明期望的响应格式)、Observe(编号 6,值为 0 表示注册观察、1 表示取消观察)、Block1/Block2(编号 27/23,用于分块传输大负载)、ETag(编号 4,用于缓存校验)。
响应码(Response Code)位于 Code 字段,格式为“类别.明细”,如 2.05。2.xx 表示成功,4.xx 表示客户端错误,5.xx 表示服务端错误。常见取值:2.01 Created、2.02 Deleted、2.04 Changed、2.05 Content、4.00 Bad Request、4.01 Unauthorized、4.04 Not Found、4.05 Method Not Allowed、5.00 Internal Server Error。
二、LwM2M 操作到 CoAP 请求的映射规则
LwM2M 在 CoAP 之上定义了一套 REST 风格的资源模型,路径形如 /{Object ID}/{Object Instance ID}/{Resource ID},例如 /3/0/0 表示设备对象(Object 3)第 0 个实例的制造商资源。映射规则可以归纳为“操作决定方法,路径决定 Uri-Path,语义决定选项”。
注册(Register):客户端向服务器发送 POST /rd?ep={Endpoint Client Name}<={Lifetime}&b=U。其中 ep 是端点名,lt 是注册有效期(秒),b=U 表示使用 UDP 传输。服务器成功后在 2.01 Created 响应的 Location-Path 选项中返回注册位置,如 /rd/5a3f,后续 Update 和 Deregister 都基于该位置。
更新(Update):POST /rd/{location},可携带新的 lt 参数续期。若注册过期前未更新,服务器会将该端点标记为离线。
注销(Deregister):DELETE /rd/{location},正常返回 2.02 Deleted。
读取(Read):GET /{obj}/{inst}/{res},成功返回 2.05 Content,负载格式由 Accept 选项协商,通常为 SenML+CBOR(Content-Format 11542)或 TLV(11542 之外的 11542 需按实现确认,常见 TLV 为 11542 的替代编码)。
写入(Write):PUT /{obj}/{inst}/{res},负载为待写入值,成功返回 2.04 Changed。若资源为只读,服务器返回 4.05 Method Not Allowed。
执行(Execute):POST /{obj}/{inst}/{res},用于触发固件升级、重启等动作,成功返回 2.04 Changed。
发现(Discover):GET /{obj},服务器返回该对象下可访问的资源列表及属性,响应 Content-Format 为 application/link-format(40)。
观察(Observe)与通知(Notify):客户端发送 GET /{obj}/{inst}/{res} 并携带 Observe: 0 选项注册观察。此后资源变化时,服务器主动发送 2.05 Content 响应,且 Observe 选项值按 24 位序号递增,客户端据此判断通知的新旧顺序。取消观察时发送 GET 并携带 Observe: 1,或直接发送 RST。
三、抓包分析:从一条 Read 看完整交互
下面以一次“读取设备制造商”为例,说明抓包中应观察的字段。假设客户端端点名为 urn:dev:001,服务器地址为 coap://lwm2m.example.com:5683。
# 客户端 → 服务器(CON 请求)
Code: 0.01 (GET)
Type: 0 (CON)
Message ID: 0x1a2b
Token: 0x7f3c
Options:
Uri-Path: "3"
Uri-Path: "0"
Uri-Path: "0"
Accept: 11542 (application/senml+cbor)
# 服务器 → 客户端(ACK 响应)
Code: 2.05 (Content)
Type: 2 (ACK)
Message ID: 0x1a2b ← 与请求一致,完成匹配
Token: 0x7f3c ← 与请求一致,完成匹配
Options:
Content-Format: 11542
Payload: SenML CBOR 编码的制造商字符串
抓包时重点核对三处:Message ID 用于 CON/ACK 配对,Token 用于请求与响应的业务匹配(尤其在 NON 或分块场景下),Uri-Path 选项的拼接顺序必须与 LwM2M 路径一致。若响应为 4.04 Not Found,通常说明对象或实例未在注册时声明;若为 4.01 Unauthorized,则需检查 DTLS 握手或服务器侧鉴权配置。
四、映射速查表
| LwM2M 操作 | CoAP 方法 | 典型路径 | 关键选项 | 成功响应码 |
|---|---|---|---|---|
| Register | POST | /rd?ep=…<=…&b=U | Uri-Query | 2.01 Created |
| Update | POST | /rd/{loc} | Uri-Query(lt) | 2.04 Changed |
| Deregister | DELETE | /rd/{loc} | — | 2.02 Deleted |
| Read | GET | /{obj}/{inst}/{res} | Accept | 2.05 Content |
| Write | PUT | /{obj}/{inst}/{res} | Content-Format | 2.04 Changed |
| Execute | POST | /{obj}/{inst}/{res} | Content-Format | 2.04 Changed |
| Discover | GET | /{obj} | Accept(40) | 2.05 Content |
| Observe | GET | /{obj}/{inst}/{res} | Observe:0 | 2.05 Content |
| Notify | —(服务器主动) | /{obj}/{inst}/{res} | Observe:序号 | 2.05 Content |
掌握这张映射表后,开发 LwM2M 设备端时就可以把“业务动作”直接翻译为“CoAP 报文构造”:先确定方法与路径,再选择消息类型(注册、写操作优先 CON,周期上报可用 NON),最后按需附加 Content-Format、Accept、Observe 等选项。抓包验证时,只要 Message ID、Token、Uri-Path、响应码四者自洽,就说明映射链路正确。