2.1 MQTT控制包的结构
MQTT协议通过以定义的方式交换一系列MQTT控制数据包来工作。本节介绍这些数据包的格式。
MQTT控制包最多由三部分组成,总是按照以下顺序组成,如图2.1所示 - MQTT控制包的结构。
固定标头,存在于所有MQTT控制数据包中 |
变量头,存在于某些MQTT控制包中 |
有效负载,存在于某些MQTT控制数据包中 |
2.2固定标题
每个MQTT控制包都包含一个固定的头。图2.2-固定标题格式说明了固定标题格式。
位 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
字节1 |
MQTT控制包类型 |
特定于每个MQTT控制数据包类型的标志 |
||||||
字节2 ... |
剩余长度 |
2.2.1 MQTT控制包类型
位置:字节1,位7-4。
表示为4位无符号值,值列于表2.1 - 控制数据包类型。
名称 |
值 |
流动方向 |
描述 |
|
Reserved | 0 |
被禁止 |
保留的 |
|
CONNECT |
1 |
客户端到服务器 |
客户端请求连接到服务器 |
|
CONNACK |
2 |
服务器到客户端 |
连接确认 |
|
PUBLISH |
3 |
客户端到服务器 或 服务器到客户端 |
发布消息 |
|
PUBACK |
4 |
客户端到服务器 或 服务器到客户端 |
发布确认 |
|
PUBREC |
五 |
客户端到服务器 或 服务器到客户端 |
收到发布(保证交付第1部分) |
|
PUBREL |
6 |
客户端到服务器 或 服务器到客户端 |
发布发布(保证交付第2部分) |
|
PUBCOMP |
7 |
客户端到服务器 或 服务器到客户端 |
发布完整(保证交付第3部分) |
|
SUBSCRIBE | 8 |
客户端到服务器 |
客户订阅请求 |
|
SUBACK |
9 |
服务器到客户端 |
订阅确认 |
|
UNSUBSCRIBE | 10 |
客户端到服务器 |
取消订阅请求 |
|
UNSUBACK |
11 |
服务器到客户端 |
取消订阅确认 |
|
PINGREQ |
12 |
客户端到服务器 |
PING请求 |
|
PINGRESP |
13 |
服务器到客户端 |
PING响应 |
|
DISCONNECT |
14 |
客户端到服务器 |
客户端优雅断开并告诉服务器 |
|
Reserved | 15 |
被禁止 |
保留的 |
|
2.2.2 Flags 标志
固定报头中字节1的其余位[3-0]包含特定于每个MQTT控制包类型的标志,如下面的表2.2-标志位所列。如果标志位在表2.2中标记为“保留” - 标志位,则保留供将来使用,并且必须设置为该表 [MQTT-2.2.2-1]中列出的值。如果收到无效标志,接收方必须关闭网络连接[MQTT-2.2.2-2] 。有关处理错误的详细信息,请参见第4.8 节
控制包 |
固定标头标志 |
第3位 |
第2位 |
第1位 |
位0 |
CONNECT |
保留的 |
0 |
0 |
0 |
0 |
CONNACK |
保留的 |
0 |
0 |
0 |
0 |
PUBLISH |
用于MQTT 3.1.1 |
DUP 1 |
QoS 2 |
QoS 2 |
保留3 |
PUBACK |
保留的 |
0 |
0 |
0 |
0 |
PUBREC |
保留的 |
0 |
0 |
0 |
0 |
PUBREL |
保留的 |
0 |
0 |
1 |
0 |
PUBCOMP |
保留的 |
0 |
0 |
0 |
0 |
SUBSCRIBE | 保留的 |
0 |
0 |
1 |
0 |
SUBACK |
保留的 |
0 |
0 |
0 |
0 |
UNSUBSCRIBE | 保留的 |
0 |
0 |
1 |
0 |
UNSUBACK |
保留的 |
0 |
0 |
0 |
0 |
PINGREQ |
保留的 |
0 |
0 |
0 |
0 |
PINGRESP |
保留的 |
0 |
0 |
0 |
0 |
DISCONNECT | 保留的 |
0 |
0 |
0 |
0 |
DUP 1 =重复发送发布控制包
QoS 2 =发布服务质量
RETAIN 3 = 发布保留标志
有关PUBLISH控制包中DUP,QoS和RETAIN标志的说明,请参见第3.3.1节。
2.2.3 Remaining Length 剩余长度
位置:从字节2开始。
剩余长度是当前数据包中剩余的字节数,包括变量头和有效负载中的数据。剩余长度不包括用于编码剩余长度的字节。
剩余长度使用可变长度编码方案进行编码,该方案使用单个字节用于最多127的值。较大的值按如下方式处理。每个字节的最低有效7位对数据进行编码,最高有效位用于指示表示中有后续字节。因此,每个字节编码128个值和“连续位”。“剩余长度”字段中的最大字节数为四。
非规范性评论
例如,64位十进制编码为单字节,十进制值64,十六进制0x40。数字321十进制(= 65 + 2 * 128)被编码为两个字节,最不重要的是第一个。第一个字节是65 + 128 = 193.注意,最高位设置为至少指示一个后续字节。第二个字节是2。
非规范性评论
这允许应用程序发送大小高达268,435,455(256 MB)的控制数据包。这个数字在线上的表示是:0xFF,0xFF,0xFF,0x7F。
表2.4显示了由增加的字节数表示的剩余长度值。
数字 |
从 |
至 |
1 |
0(0x00) |
127(0x7F) |
2 |
128(0x80,0x01) |
16 383(0xFF,0x7F) |
3 |
16 384(0x80,0x80,0x01) |
2 097 151(0xFF,0xFF,0x7F) |
4 |
2 097 152(0x80,0x80,0x80,0x01) |
268 435 455(0xFF,0xFF,0xFF,0x7F) |
非规范性评论
将非负整数(X)编码为可变长度编码方案的算法如下:
do 283
encodedByte = X MOD 128 284
X = X DIV 128 285
// if there are more data to encode, set the top bit of this byte 286
if ( X > 0 ) 287
encodedByte = encodedByte OR 128 288
endif 289
'output' encodedByte 290
while ( X > 0 )
其中MOD是模运算符(C中的%),DIV 是整数除法(/在C中),OR是按位或(|在C中)。
非规范性评论
解码剩余长度字段的算法如下:
multiplier = 1 299
value = 0 300
do 301
encodedByte = 'next byte from stream' 302
value += (encodedByte AND 127) * multiplier 303
multiplier *= 128 304
if (multiplier > 128*128*128) 305
throw Error(Malformed Remaining Length) 306
while ((encodedByte AND 128) != 0)
其中AND是按位和运算符(& in C)。
当此算法终止时,value包含Remaining Length值。
2.3 Variable header 变量头
某些类型的MQTT控制数据包包含可变标头组件。它位于固定标头和有效负载之间。变量头的内容根据数据包类型而有所不同。变量头的包标识符字段在几种包类型中是通用的。
2.3.1包标识符
位 |
7 |
6 |
五 |
4 |
3 |
2 |
1 |
0 |
字节1 |
包标识符MSB |
|||||||
字节2 |
包标识符LSB |
许多控制分组类型的可变报头组件包括2字节分组标识符字段。这些控制数据包是PUBLISH(其中QoS> 0),PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE,UNSUBACK。
SUBSCRIBE,UNSUBSCRIBE和PUBLISH(在QoS> 0的情况下)控制数据包必须包含非零的16位数据包标识符 [MQTT-2.3.1-1]。每次客户端发送这些类型之一的新数据包时,它必须为其分配当前未使用的数据包标识符 [MQTT-2.3.1-2]。如果客户端重新发送特定的控制数据包,那么它必须在后续重新发送该数据包时使用相同的数据包标识符。客户端处理完相应的确认数据包后,数据包标识符可以重用。在QoS 1 PUBLISH的情况下,这是相应的PUBACK; 在QoS 2的情况下,它是PUBCOMP。对于SUBSCRIBE或UNSUBSCRIBE,它是相应的SUBACK或UNSUBACK [MQTT-2.3.1-3]。 当服务器发送QoS> 0 [MQTT-2.3.1-4] 的PUBLISH时,相同的条件适用于服务器。
如果其QoS值设置为0,则PUBLISH数据包 不得包含数据包标识符[MQTT-2.3.1-5]。
PUBACK,PUBREC或PUBREL数据包必须包含与最初发送的PUBLISH数据包相同的数据包标识符 [MQTT-2.3.1-6]。类似地,SUBACK和UNSUBACK必须包含分别在相应的SUBSCRIBE和UNSUBSCRIBE数据包中使用的数据包标识符 [MQTT-2.3.1-7]。
表2.5 - 包含数据包标识符的控制数据包中列出了需要数据包标识符的控制数据包。
控制包 |
数据包标识符字段 |
CONNECT |
没有 |
CONNACK |
没有 |
PUBLISH | 是(如果QoS> 0) |
PUBACK |
是 |
PUBREC |
是 |
PUBREL |
是 |
PUBCOMP |
是 |
SUBSCRIBE | |
SUBACK |
是 |
UNSUBSCRIBE | 是 |
UNSUBACK |
是 |
PINGREQ |
没有 |
PINGRESP |
没有 |
DISCONNECT | 没有 |
客户端和服务器彼此独立地分配数据包标识符。因此,客户端服务器对可以使用相同的数据包标识符参与并发消息交换。
非规范性评论
客户端可以发送带有数据包标识符0x1234的PUBLISH数据包,然后在收到其发送的PUBLISH的PUBACK之前,从其服务器接收带有数据包标识符0x1234的不同PUBLISH。
客户端服务器
PUBLISH Packet Identifier = 0x1234 --- à
ß -发布数据包标识符= 0x1234
PUBACK数据包标识符= 0x1234 --- à
ß-- PUBACK数据包标识符= 0x1234
2.4 Payload 有效载荷
某些MQTT控制数据包包含有效负载作为数据包的最后部分,如第3章所述。在PUBLISH数据包的情况下,这是应用程序消息。表2.6 - 包含有效负载的控制数据包列出了需要有效负载的控制数据包。
控制包 |
有效载荷 |
CONNECT |
需要 |
CONNACK |
没有 |
PUBLISH | 可选的 |
PUBACK |
没有 |
PUBREC |
没有 |
PUBREL |
没有 |
PUBCOMP |
没有 |
SUBSCRIBE | 需要 |
SUBACK |
需要 |
UNSUBSCRIBE | 需要 |
UNSUBACK |
没有 |
PINGREQ |
没有 |
PINGRESP |
没有 |
DISCONNECT | 没有 |
里面可能有些google翻译不准的地方请大家多多指正!