第 2 章 · 03 可变报头与报文标识符 本节摘要:可变报头的内容随报文类型而变,但其中有一个贯穿全协议的通用字段——报文标识符(Packet Identifier)。它是 2 字节编号,是 QoS 1/2 可靠投递、订阅/退订确认的"快递单号"。本节讲清:哪些报文需要它、哪些禁止有它、标识符的分配/重用/零值禁令,以及客户端与服务端为何各自独立编号。读完本节,你应当能说出任意一种报文的标识符规则。 学习目标 阅读完本节,你应当能够: 列出需要报文标识符的 9 种报文,以及明确禁止它的报文(PUBLISH QoS 0)。 解释报文标识符的分配规则:非零、未使用、重发复用、确认后释放。 说明客户端与服务端独立分配标识符为什么不会冲突。
本节摘要:可变报头的内容随报文类型而变,但其中有一个贯穿全协议的通用字段——报文标识符(Packet Identifier)。它是 2 字节编号,是 QoS 1/2 可靠投递、订阅/退订确认的"快递单号"。本节讲清:哪些报文需要它、哪些禁止有它、标识符的分配/重用/零值禁令,以及客户端与服务端为何各自独立编号。读完本节,你应当能说出任意一种报文的标识符规则。
阅读完本节,你应当能够:
可变报头位于固定报头与有效载荷之间,内容完全由报文类型决定:
报文标识符是 2 字节无符号整数,范围 1 ~ 65535(0 非法)。它的作用是让请求与确认一一对应:发送方带着单号发请求,接收方把同一个单号写进确认报文,双方就能把"这条确认"和"那次请求"对上。
需要报文标识符的报文(9 种):
| 报文 | 标识符规则 |
|---|---|
| PUBLISH | 需要(仅当 QoS > 0);QoS 0 禁止携带 |
| PUBACK / PUBREC / PUBREL / PUBCOMP | 必须与最初那条 PUBLISH 的标识符相同 |
| SUBSCRIBE / SUBACK | SUBACK 必须回显 SUBSCRIBE 的标识符 |
| UNSUBSCRIBE / UNSUBACK | UNSUBACK 必须回显 UNSUBSCRIBE 的标识符 |
不需要(也禁止携带)报文标识符的报文:CONNECT、CONNACK、PINGREQ、PINGRESP、DISCONNECT,以及 QoS 0 的 PUBLISH。
协议对标识符的使用有严格约束:
规则的深层用意:标识符是在途请求的编号,不是全局唯一 ID。它只在"请求-确认"的生命周期内有效,用完即回收——就像餐馆的一次性排队号,取餐后就能给下一位客人用。
客户端和服务端彼此独立地分配报文标识符 [MQTT-2.3.1-4]。也就是说,同一时刻,客户端发出的单号 0x1234 与服务端发出的单号 0x1234 是两条完全不同的在途请求,互不干扰。
协议甚至允许这样的交错:客户端发出标识符 0x1234 的 PUBLISH,还没等到 PUBACK,就收到服务端发来的另一条标识符同样为 0x1234 的 PUBLISH。因为两个方向各自计数,接收方只需要按"自己发出的单号"来匹配确认,不会认错。
| 方向 | 报文示例 | 标识符 |
|---|---|---|
| 客户端→服务端 | PUBLISH | 0x1234 |
| 服务端→客户端 | PUBLISH(另一条消息) | 0x1234 |
| 客户端→服务端 | PUBACK(回应服务端那条) | 0x1234 |
| 服务端→客户端 | PUBACK(回应客户端那条) | 0x1234 |
QoS 2 的投递需要四步握手:PUBLISH → PUBREC → PUBREL → PUBCOMP,四步携带同一个标识符。这保证了:
第 4 章会完整推演 QoS 2 的状态机,这里先记住:报文标识符是"让消息在复杂网络里不丢不重"的编号基础。
报文标识符是 MQTT 可靠投递机制的"单号系统":非零、唯一、重发复用、确认释放。它只用于 QoS > 0 的 PUBLISH 和订阅/退订类报文,其余报文一律不携带。下一章逐个报文拆解时,你会反复看到这 2 字节的身影。