第二章 MQTT控制报文格式 MQTT Control Packet format

目录

2.1 MQTT控制报文结构 Structure of an MQTT Control Packet

MQTT协议通过交换预定义的MQTT控制报文来通信。这一节描述这些报文的格式。

MQTT控制报文由三部分组成,按照下图描述的顺序:

图 2-1 - MQTT控制报文的结构 Structure of an MQTT Control Packet
Fixed Header固定报头,所有控制报文都包含
Variable Header 可变报头,部分控制报文包含
Payload 有效载荷,部分控制报文包含

2.1.1 固定报头 Fixed header

如下图所示,每个MQTT控制报文都包含一个固定报头。

图 2-2 - 固定报头的格式 Fixed Header format
比特位 7 6 5 4 3 2 1 0
byte 1 MQTT控制报文的类型 用于指定控制报文类型的标志位
byte 2… 剩余长度

2.1.2 MQTT控制报文的类型 MQTT Control Packet type

位置: 第1个字节,二进制位7-4。

表示为4位无符号值,这些值的定义见下表。

表 2-1 - MQTT控制报文的类型 MQTT Control Packet types
名字 报文流动方向 描述
Reserved 0 禁止 保留
CONNECT 1 客户端到服务端 客户端请求连接服务端
CONNACK 2 服务端到客户端 连接报文确认
PUBLISH 3 两个方向都允许 发布消息
PUBACK 4 两个方向都允许 QoS 1消息发布收到确认
PUBREC 5 两个方向都允许 发布收到(保证交付第一步)
PUBREL 6 两个方向都允许 发布释放(保证交付第二步)
PUBCOMP 7 两个方向都允许 QoS 2消息发布完成(保证交互第三步)
SUBSCRIBE 8 客户端到服务端 客户端订阅请求
SUBACK 9 服务端到客户端 订阅请求报文确认
UNSUBSCRIBE 10 客户端到服务端 客户端取消订阅请求
UNSUBACK 11 服务端到客户端 取消订阅报文确认
PINGREQ 12 客户端到服务端 心跳请求
PINGRESP 13 服务端到客户端 心跳响应
DISCONNECT 14 两个方向都允许 断开连接通知
AUTH 15 两个方向都允许 认证信息交换

### 2.1.3 标志 Flags 固定报头第1个字节的剩余的4位 [3-0]包含每个 MQTT 控制报文类型特定的标志如下表所示。表格中任何标记为“保留”的标志位,都是保留给以后使用的,必须设置为表格中列出的值 [MQTT-2.1.3-1]。如果收到非法的标志,此报文被当做无效报文。有关错误处理的详细信息见 4.8节 [MQTT-2.2.2-2]。 ##### 表 2-2 - 标志位 Flag Bits
控制报文 固定报头标志 Bit 3 Bit 2 Bit 1 Bit 0
CONNECT Reserved 0 0 0 0
CONNACK Reserved 0 0 0 0
PUBLISH Used in MQTT v5.0 DUP QoS RETAIN
PUBACK Reserved 0 0 0 0
PUBREC Reserved 0 0 0 0
PUBREL Reserved 0 0 1 0
PUBCOMP Reserved 0 0 0 0
SUBSCRIBE Reserved 0 0 1 0
SUBACK Reserved 0 0 0 0
UNSUBSCRIBE Reserved 0 0 1 0
UNSUBACK Reserved 0 0 0 0
PINGREQ Reserved 0 0 0 0
PINGRESP Reserved 0 0 0 0
DISCONNECT Reserved 0 0 0 0
AUTH Reserved 0 0 0 0
  • DUP1 =控制报文的重复分发标志
  • QoS2 = PUBLISH报文的服务质量等级
  • RETAIN3 = PUBLISH报文的保留标志 PUBLISH控制报文中的DUP, QoS和RETAIN标志的描述见 3.3.1节。

2.1.4 剩余长度 Remaining Length

位置: 从第2个字节开始。

剩余长度(Remaining Length)是一个变长字节整数,用来表示当前控制报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。MQTT控制报文总长度等于固定报头的长度加上剩余长度。

2.2 可变报头 Variable header

某些 MQTT 控制报文包含一个可变报头部分。它在固定报头和有效载荷之间。可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。

2.2.1 报文标识符 Packet Identifier

部分类型MQTT控制报文的可变报头部分包含了2个字节的报文标识符字段。这些MQTT控制报文类型为:PUBLISH报文(当QoS>0时),PUBACK,PUBREC,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE,UNSUBACK。

需要报文标识符的MQTT控制报文如下表所示。

表 2-3 - 包含报文标识符的MQTT控制报文 MQTT Control Packets that contain a Packet Identifier
名字
CONNECT 不需要
CONNACK 不需要
PUBLISH 需要(如果QoS>0)
PUBACK 需要
PUBREC 需要
PUBREL 需要
PUBCOMP 需要
SUBSCRIBE 需要
SUBACK 需要
UNSUBSCRIBE 需要
UNSUBACK 需要
PINGREQ 不需要
PINGRESP 不需要
DISCONNECT 不需要
AUTH 不需要
QoS设置为0的 PUBLISH 报文不能包含报文标识符[MQTT-2.2.1-2]。 客户端每次发送一个新的SUBSCRIBE,UNSUBSCRIBE或者PUBLISH(当QoS>0时)MQTT控制报文时都必须分配一个当前未使用的非零报文标识符 [MQTT-2.2.1-3]。 服务端每次发送一个新的PUBLISH(当QoS>0)MQTT控制报文时都必须分配一个当前未使用的非零报文标识符 [MQTT-2.2.1-4]。 当客户端处理完这个报文对应的确认后,这个报文标识符就释放可重用。QoS 1的PUBLISH对应的是PUBACK,QoS 2的PUBLISH对应的是包含原因码128以上的PUBCOMP或PUBREC,与SUBSCRIBE或UNSUBSCRIBE对应的分别是SUBACK或UNSUBACK。 PUBLISH,SUBSCRIBE和UNSUBSCRIBE的报文标识符,在一次会话中对于客户端和服务端来说分属于不同的组。某个报文标识符在某一时刻不能被多个命令所使用。 PUBACK,PUBREC和PUBREL报文必须包含与最初发送的PUBLISH报文相同的报文标识符 [MQTT-2.2.1-5]。类似地,SUBACK和UNSUBACK必须包含在对应的SUBSCRIBE和UNSUBSCRIBE报文中使用的报文标识符 [MQTT-2.2.1-6]。 客户端和服务端彼此独立地分配报文标识符。因此,客户端服务端组合使用相同的报文标识符可以实现并发的消息交换。 > 非规范评注 > > 客户端发送标识符为0x1234的PUBLISH报文,它有可能会在收到那个报文的PUBACK之前,先收到服务端发送的另一个不同的但是报文标识符也为0x1234的PUBLISH报文。
客户端 服务端
PUBLISH Packet Identifier = 0x1234—->
<—-PUBLISH Packet Identifier = 0x1234
PUBACK Packet Identifier = 0x1234—->
<—-PUBACK Packet Identifier = 0x1234

2.2.2 属性 Properties

CONNECT,CONNACK,PUBLISH,PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBACK,DISCONNECT和AUTH报文可变报头的最后一部分是一组属性。CONNECT报文的遗嘱(Will)属性字段中也包含了一组可选的属性。

属性字段由属性长度和所有属性组成。

2.2.2.1 属性长度 Property Length

属性长度被编码为变长字节整数。属性长度不包含用于编码属性长度自身的字节数,但包含所有属性的长度。如果没有任何属性,必须由属性长度为零的字段来指示 [MQTT-2.2.2-1]。

2.2.2.2 属性 Property

一个属性包含一段数据和一个定义了属性用途和数据类型的标识符。标识符被编码为变长字节整数。任何控制报文,如果包含了:对于该报文类型无效的标识符,或者错误类型的数据,都是无效报文。收到无效报文时,服务端或客户端使用包含原因码0x81(无效报文)CONNACK或DISCONNECT报文进行错误处理,如4.13节所述。标识符排序不分先后。

表 2-4 - 属性 Properties
标识符 属性名 数据类型 报文/遗嘱属性
Dec Hex
1 0x01 载荷格式说明 字节 PUBLISH, Will Properties
2 0x02 消息过期时间 四字节整数 PUBLISH, Will Properties
3 0x03 内容类型 UTF-8编码字符串 PUBLISH, Will Properties
8 0x08 响应主题 UTF-8编码字符串 PUBLISH, Will Properties
9 0x09 相关数据 二进制数据 PUBLISH, Will Properties
11 0x0B 定义标识符 变长字节整数 PUBLISH, SUBSCRIBE
17 0x11 会话过期间隔 四字节整数 CONNECT, CONNACK, DISCONNECT
18 0x12 分配客户标识符 UTF-8编码字符串 CONNACK
19 0x13 服务端保活时间 双字节整数 CONNACK
21 0x15 认证方法 UTF-8编码字符串 CONNECT, CONNACK, AUTH
22 0x16 认证数据 二进制数据 CONNECT, CONNACK, AUTH
23 0x17 请求问题信息 字节 CONNECT
24 0x18 遗嘱延时间隔 四字节整数 Will Properties
25 0x19 请求响应信息 字节 CONNECT
26 0x1A 请求信息 UTF-8编码字符串 CONNACK
28 0x1C 服务端参考 UTF-8编码字符串 CONNACK, DISCONNECT
31 0x1F 原因字符串 UTF-8编码字符串 CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK, DISCONNECT, AUTH
33 0x21 接收最大数量 双字节整数 CONNECT, CONNACK
34 0x22 主题别名最大长度 双字节整数 CONNECT, CONNACK
35 0x23 主题别名 双字节整数 PUBLISH
36 0x24 最大QoS 字节 CONNACK
37 0x25 保留属性可用性 字节 CONNACK
38 0x26 用户属性 UTF-8字符串对 CONNECT, CONNACK, PUBLISH, Will Properties, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, DISCONNECT, AUTH
39 0x27 最大报文长度 四字节整数 CONNECT, CONNACK
40 0x28 通配符订阅可用性 字节 CONNACK
41 0x29 订阅标识符可用性 字节 CONNACK
42 0x2A 共享订阅可用性 字节 CONNACK

非规范评注

尽管属性标识符用变长字节整数来表示,但在此版本协议中,所有的标识符均由一个字节来表示。

2.3 有效载荷 Payload

某些MQTT控制报文在报文的最后部分包含一个有效载荷,这将在第三章论述。对于PUBLISH来说有效载荷就是应用消息。

表 2-5 包含有效载荷的MQTT控制报文 MQTT Control Packets that contain a Payload
MQTT控制报文 有效载荷
CONNECT 需要
CONNACK 不需要
PUBLISH 可选
PUBACK 不需要
PUBREC 不需要
PUBREL 不需要
PUBCOMP 不需要
SUBSCRIBE 需要
SUBACK 需要
UNSUBSCRIBE 需要
UNSUBACK 需要
PINGREQ 不需要
PINGRESP 不需要
DISCONNECT 不需要
AUTH 不需要
## 2.4 原因码 Reason Code 原因码是一个单字节无符号数,用来指示一次操作的结果。小于0x80的原因码指示某次操作成功完成,通常用0来表示。大于等于0x80的原因码用来指示操作失败。 CONNACK,PUBACK,PUBREC,PUBREL,PUBCOMP,DISCONNECT和AUTH控制报文的可变报头有一个单字节的原因码。SUBACK和UNSUBACK报文的载荷字段包含一个或多个原因码。 原因码如下表所示。 ##### 表 2-6 - 原因码 Reason Code
原因码 名称 报文
Dec Hex
0 0x00 成功 CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, UNSUBACK, AUTH
0 0x00 正常断开 DISCONNECT
0 0x00 授权的QoS 0 SUBACK
1 0x01 授权的QoS 1 SUBACK
2 0x02 授权的QoS 2 SUBACK
4 0x04 包含遗嘱的断开 DISCONNECT
16 0x10 无匹配订阅 PUBACK, PUBREC
17 0x11 订阅不存在 UNSUBACK
24 0x18 继续认证 AUTH
25 0x19 重新认证 AUTH
128 0x80 未指明的错误 CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT
129 0x81 无效报文 CONNACK, DISCONNECT
130 0x82 协议错误 CONNACK, DISCONNECT
131 0x83 实现错误 CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT
132 0x84 协议版本不支持 CONNACK
133 0x85 客户标识符无效 CONNACK
134 0x86 用户名密码错误 CONNACK
135 0x87 未授权 CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT
136 0x88 服务端不可用 CONNACK
137 0x89 服务端正忙 CONNACK, DISCONNECT
138 0x8A 禁止 CONNACK
139 0x8B 服务端关闭中 DISCONNECT
140 0x8C 无效的认证方法 CONNACK, DISCONNECT
141 0x8D 保活超时 DISCONNECT
142 0x8E 会话被接管 DISCONNECT
143 0x8F 主题过滤器无效 SUBACK, UNSUBACK, DISCONNECT
144 0x90 主题名无效 CONNACK, PUBACK, PUBREC, DISCONNECT
145 0x91 报文标识符已被占用 PUBACK, PUBREC, SUBACK, UNSUBACK
146 0x92 报文标识符无效 PUBREL, PUBCOMP
147 0x93 接收超出最大数量 DISCONNECT
148 0x94 主题别名无效 DISCONNECT
149 0x95 报文过长 CONNACK, DISCONNECT
150 0x96 消息太过频繁 DISCONNECT
151 0x97 超出配额 CONNACK, PUBACK, PUBREC, SUBACK, DISCONNECT
152 0x98 管理行为 DISCONNECT
153 0x99 载荷格式无效 CONNACK, PUBACK, PUBREC, DISCONNECT
154 0x9A 不支持保留 CONNACK, DISCONNECT
155 0x9B 不支持的QoS等级 CONNACK, DISCONNECT
156 0x9C (临时)使用其他服务端 CONNACK, DISCONNECT
157 0x9D 服务端已(永久)移动 CONNACK, DISCONNECT
158 0x9E 不支持共享订阅 SUBACK, DISCONNECT
159 0x9F 超出连接速率限制 CONNACK, DISCONNECT
160 0xA0 最大连接时间 DISCONNECT
161 0xA1 不支持订阅标识符 SUBACK, DISCONNECT
162 0xA2 不支持通配符订阅 SUBACK, DISCONNECT

非规范评注

对于原因码0x91(报文标识符已被占用)的处理可以为尝试修复会话、以新会话标志为1重置会话或者判定客户端或服务端实现有缺陷。

项目主页