第 2 章 · 03 可变报头与报文标识符


文档摘要

第 2 章 · 03 可变报头与报文标识符 本节摘要:可变报头的内容随报文类型而变,但其中有一个贯穿全协议的通用字段——报文标识符(Packet Identifier)。它是 2 字节编号,是 QoS 1/2 可靠投递、订阅/退订确认的"快递单号"。本节讲清:哪些报文需要它、哪些禁止有它、标识符的分配/重用/零值禁令,以及客户端与服务端为何各自独立编号。读完本节,你应当能说出任意一种报文的标识符规则。 学习目标 阅读完本节,你应当能够: 列出需要报文标识符的 9 种报文,以及明确禁止它的报文(PUBLISH QoS 0)。 解释报文标识符的分配规则:非零、未使用、重发复用、确认后释放。 说明客户端与服务端独立分配标识符为什么不会冲突。

第 2 章 · 03 可变报头与报文标识符

本节摘要:可变报头的内容随报文类型而变,但其中有一个贯穿全协议的通用字段——报文标识符(Packet Identifier)。它是 2 字节编号,是 QoS 1/2 可靠投递、订阅/退订确认的"快递单号"。本节讲清:哪些报文需要它、哪些禁止有它、标识符的分配/重用/零值禁令,以及客户端与服务端为何各自独立编号。读完本节,你应当能说出任意一种报文的标识符规则。

学习目标

阅读完本节,你应当能够:

  1. 列出需要报文标识符的 9 种报文,以及明确禁止它的报文(PUBLISH QoS 0)。
  2. 解释报文标识符的分配规则:非零、未使用、重发复用、确认后释放。
  3. 说明客户端与服务端独立分配标识符为什么不会冲突。
  4. 理解报文标识符如何让 QoS 2 的"四步握手"能够关联同一个消息。

一、可变报头:按类型定制的字段区

可变报头位于固定报头与有效载荷之间,内容完全由报文类型决定:

  • CONNECT:协议名、协议级别、连接标志、保活时间(第 3 章细讲);
  • CONNACK:连接确认标志、返回码;
  • PUBLISH:主题名(UTF-8 字符串)、报文标识符(QoS > 0 时);
  • PUBACK/PUBREC/PUBREL/PUBCOMP:仅 2 字节报文标识符;
  • SUBSCRIBE/SUBACK/UNSUBSCRIBE/UNSUBACK:仅 2 字节报文标识符;
  • PINGREQ/PINGRESP/DISCONNECT:没有可变报头

二、报文标识符: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。

三、分配、复用与释放的硬性规则

协议对标识符的使用有严格约束:

  1. 非零:SUBSCRIBE、UNSUBSCRIBE 以及 QoS > 0 的 PUBLISH 必须携带非零标识符 [MQTT-2.3.1-1]。
  2. 未使用:发送方每次发送这类报文,必须分配一个当前未使用的标识符 [MQTT-2.3.1-2]——即"在途"的每个请求单号唯一。
  3. 重发复用:如果因网络问题需要重发某个控制报文,必须使用相同的标识符 [MQTT-2.3.1-2]。这是接收方去重的基础:看到重复单号,就知道是重发,不是新消息。
  4. 确认后释放:当收到对应的确认报文后,该标识符即可释放重用。各报文的"确认"对应关系:QoS 1 的 PUBLISH ↔ PUBACK;QoS 2 的 PUBLISH ↔ PUBCOMP;SUBSCRIBE ↔ SUBACK;UNSUBSCRIBE ↔ UNSUBACK [MQTT-2.3.1-3]。
  5. 回显一致:PUBACK/PUBREC/PUBREL 必须携带与最初 PUBLISH 相同的标识符 [MQTT-2.3.1-6];SUBACK/UNSUBACK 同理 [MQTT-2.3.1-7]。

规则的深层用意:标识符是在途请求的编号,不是全局唯一 ID。它只在"请求-确认"的生命周期内有效,用完即回收——就像餐馆的一次性排队号,取餐后就能给下一位客人用。

四、客户端与服务端为何独立编号

客户端和服务端彼此独立地分配报文标识符 [MQTT-2.3.1-4]。也就是说,同一时刻,客户端发出的单号 0x1234 与服务端发出的单号 0x1234 是两条完全不同的在途请求,互不干扰。

协议甚至允许这样的交错:客户端发出标识符 0x1234 的 PUBLISH,还没等到 PUBACK,就收到服务端发来的另一条标识符同样为 0x1234 的 PUBLISH。因为两个方向各自计数,接收方只需要按"自己发出的单号"来匹配确认,不会认错。

方向 报文示例 标识符
客户端→服务端 PUBLISH 0x1234
服务端→客户端 PUBLISH(另一条消息) 0x1234
客户端→服务端 PUBACK(回应服务端那条) 0x1234
服务端→客户端 PUBACK(回应客户端那条) 0x1234

五、标识符在 QoS 2 中的作用预览

QoS 2 的投递需要四步握手:PUBLISH → PUBREC → PUBREL → PUBCOMP,四步携带同一个标识符。这保证了:

  • 发送方知道这条 PUBREC 回应的是哪条 PUBLISH;
  • 接收方通过标识符识别 PUBREL,并据此只交付一次;
  • 任何一步超时,重发的报文仍带同一标识符,接收方能够识别并去重。

第 4 章会完整推演 QoS 2 的状态机,这里先记住:报文标识符是"让消息在复杂网络里不丢不重"的编号基础。

小结

报文标识符是 MQTT 可靠投递机制的"单号系统":非零、唯一、重发复用、确认释放。它只用于 QoS > 0 的 PUBLISH 和订阅/退订类报文,其余报文一律不携带。下一章逐个报文拆解时,你会反复看到这 2 字节的身影。


发布者: 作者: 灏天文库 转发
评论区 (0)
U