- 第一章 - 介绍
- 第二章 – MQTT控制报文格式
- 第三章 – MQTT控制报文
- 第四章 – 操作行为
- 第五章 – 安全(非规范)
- 第六章 – 使用WebSocket作为网络层
- 第七章 – 一致性
- 附录B - 强制性规范声明(非规范)
- 附录C - MQTT v5.0新特性总结(非规范)
MQTT协议通过交换预定义的MQTT控制报文来通信。这一节描述这些报文的格式。
MQTT控制报文由三部分组成,按照下图描述的顺序:
Fixed Header固定报头,所有控制报文都包含 |
Variable Header 可变报头,部分控制报文包含 |
Payload 有效载荷,部分控制报文包含 |
如下图所示,每个MQTT控制报文都包含一个固定报头。
比特位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
byte 1 | MQTT控制报文的类型 | 用于指定控制报文类型的标志位 | ||||||
byte 2... | 剩余长度 |
位置: 第1个字节,二进制位7-4。
表示为4位无符号值,这些值的定义见下表。
名字 | 值 | 报文流动方向 | 描述 |
---|---|---|---|
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 | 两个方向都允许 | 认证信息交换 |
固定报头第1个字节的剩余的4位 [3-0]包含每个 MQTT 控制报文类型特定的标志如下表所示。表格中任何标记为“保留”的标志位,都是保留给以后使用的,必须设置为表格中列出的值 [MQTT-2.1.3-1]。如果收到非法的标志,此报文被当做无效报文。有关错误处理的详细信息见 4.8节 [MQTT-2.2.2-2]。
控制报文 | 固定报头标志 | 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个字节开始。
剩余长度(Remaining Length)是一个变长字节整数,用来表示当前控制报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。MQTT控制报文总长度等于固定报头的长度加上剩余长度。
某些 MQTT 控制报文包含一个可变报头部分。它在固定报头和有效载荷之间。可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。
部分类型MQTT控制报文的可变报头部分包含了2个字节的报文标识符字段。这些MQTT控制报文类型为:PUBLISH报文(当QoS>0时),PUBACK,PUBREC,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE,UNSUBACK。
需要报文标识符的MQTT控制报文如下表所示。
名字 | 值 |
---|---|
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 |
CONNECT,CONNACK,PUBLISH,PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBACK,DISCONNECT和AUTH报文可变报头的最后一部分是一组属性。CONNECT报文的遗嘱(Will)属性字段中也包含了一组可选的属性。
属性字段由属性长度和所有属性组成。
属性长度被编码为变长字节整数。属性长度不包含用于编码属性长度自身的字节数,但包含所有属性的长度。如果没有任何属性,必须由属性长度为零的字段来指示 [MQTT-2.2.2-1]。
一个属性包含一段数据和一个定义了属性用途和数据类型的标识符。标识符被编码为变长字节整数。任何控制报文,如果包含了:对于该报文类型无效的标识符,或者错误类型的数据,都是无效报文。收到无效报文时,服务端或客户端使用包含原因码0x81(无效报文)CONNACK或DISCONNECT报文进行错误处理,如4.13节所述。标识符排序不分先后。
标识符 | 属性名 | 数据类型 | 报文/遗嘱属性 | |
---|---|---|---|---|
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 |
非规范评注
尽管属性标识符用变长字节整数来表示,但在此版本协议中,所有的标识符均由一个字节来表示。
某些MQTT控制报文在报文的最后部分包含一个有效载荷,这将在第三章论述。对于PUBLISH来说有效载荷就是应用消息。
MQTT控制报文 | 有效载荷 |
---|---|
CONNECT | 需要 |
CONNACK | 不需要 |
PUBLISH | 可选 |
PUBACK | 不需要 |
PUBREC | 不需要 |
PUBREL | 不需要 |
PUBCOMP | 不需要 |
SUBSCRIBE | 需要 |
SUBACK | 需要 |
UNSUBSCRIBE | 需要 |
UNSUBACK | 需要 |
PINGREQ | 不需要 |
PINGRESP | 不需要 |
DISCONNECT | 不需要 |
AUTH | 不需要 |
原因码是一个单字节无符号数,用来指示一次操作的结果。小于0x80的原因码指示某次操作成功完成,通常用0来表示。大于等于0x80的原因码用来指示操作失败。
CONNACK,PUBACK,PUBREC,PUBREL,PUBCOMP,DISCONNECT和AUTH控制报文的可变报头有一个单字节的原因码。SUBACK和UNSUBACK报文的载荷字段包含一个或多个原因码。
原因码如下表所示。
原因码 | 名称 | 报文 | |
---|---|---|---|
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重置会话或者判定客户端或服务端实现有缺陷。