概述
推荐一款稳定的基于C编写的MQTT Client开源库 cMQTT
MQTT协议详解及开发教程(一)MQTT协议概述
MQTT协议详解及开发教程(二)MQTT服务器EMQx搭建
MQTT协议详解及开发教程(三)MQTT Client工具软件选择及简单测试
前言
在前面的文章中,我们对MQTT的应用场景,MQTT服务器搭建、MQTT client工具测试进行了简单的描述,对MQTT有了初步的了解,从本文开始,将会详细的分析MQTT协议内容。
1.MQTT 控制报文结构
名称 | 备注 |
---|---|
Fixed header固定头 | 所有的控制报文都包含 |
Variable header可变报头 | 部分控制报文包含 |
Payload有效载荷 | 部分控制报文包含 |
2 固定头
每个MQTT控制报文都包含了一个固定头,下图描述了固定头的格式
2.1 MQTT控制报文类型
位置:第1个字节,第4~7bit,共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 | 客户端到服务端 | 客户端断开连接 |
Reserved | 15 | 禁止 | 保留 |
2.2 控制报文标志
固定报头的第1个字节的剩余4位[3-0]包含了每个MQTT控制报文类型特定的标志,如果收到非法的标志,接收者必须关闭网络连接,标志如下,其中任何标记为“Reserved”的标志位,都是保留给以后使用的。
其中:
DUP = 控制报文的重复分发标志
QoS = PUBLISH报文的服务质量等级
RETAIN = PUBLISH报文的保留标志
2.3 剩余长度
位置:从第2个字节开始
剩余长度表示当前报文剩余部分的字节数,包括可变报头和负载数据。剩余长度不包括用于编码剩余长度字段本身的字节数。
剩余长度字段使用了一个变长度编码方案,对于小于128的值,它使用单字节编码,更大的值则按下面的方式处理:
低7位有效位用于编码数据,最高有效位用于指示是否有更多的字节。因此每个字节可以编码128个(0-127/0x00-0x7F)数值和一个延续位(continuation bit),剩余长度的字段最大4个字节。
举例1:十进制数64,由于小于127,所以会被编码为1个字节,对应的十六进制为 0x40
举例2:十进制321(=65+2128),所以会被编码为2个字节,最低有效位在前,
第1个字节为 65+128 =193,注意这里的128是表示其最高位为1,表示后面还有字节。
第2个字节为2,表示 2128 = 256,
所以本例中的剩余长度编码为 0xC1,0x02,我们去计算的时候是这样:
len = 0xC1&0X7F + 0x02*0x7F // 321
下表中描述了不同字节数表示的剩余长度大小
字节数 | 最小值 | 最大值 |
---|---|---|
1 | 0(0x00) | 127(0x7F) |
2 | 128(0x80, 0x01) | 16383(0xFF,0x7F) |
3 | 16384(0x80, 0x80, 0x01) | 2097151(0xFF, 0xFF, 0x7F) |
4 | 2097152(0x80, 0x80, 0x80, 0x01) | 268435455(0xFF, 0xFF, 0xFF, 0x7F) |
所以MQTT协议 理论上允许发送最大 256MB(268435455)大小的控制报文。
3. 可变报头
某些MQTT控制报文包含了一个可变报头部分,它在固定报头和负载之间,可变报头的内容根据报文类型的不同而不同,可变报头的报文标识符(Packet Identifier)字段存在与多个类型的报文里。
可变报头其实就是MQTT开发中使用的 Packet ID,通过Packet ID 进行一些操作确认。
3.1 报文标识符
报文标识符类型
很多控制报文的可变报头部分包含了两字节的报文标识符字段,这些报文是PUBLISH(QoS>0时),PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCIBE, UNSUBACK.
SUBSCRIBE, UNSUBSCRIBE和PUBLISH(QoS > 0)控制报文必须包含一个非零的16位报文标识符(Packet ID)。客户端每次发送一个新的这些类型报文时,都必须分配一个当前未使用的报文标识符(我们在开发的时候可以做简单的 自增packet_id++)。如果一个客户端要重发这个特殊的控制报文,爱随后重发的那个报文时,它必须使用相同的标识符。当客户端处理完这个报文对应的确认后,这个报文标识符就可以释放了,也就是可以重新使用。
Qos1的PUBLISH 对应的是PUBACK, Qos2的PUBLISH 对应的是PUBCOMP, 与SUBCRIBE或UNSUBSCRIBE对应的分别是SUBACK或UNSUBACK,服务器返回的Packet ID与客户端发送的是一致的,通过这一机制来实现确认。
Qos设置为0的PUBLISH报文不能包含报文标识符。
PUBACK, PUBREC, PUBREL报文必须包含于最初发送的PUBLISH报文相同的报文描述符,同样的,SUBACK和UNSUBACK必须包含在对应的SUBSCRIBE和UNSUBSCRIBE报文中使用的标识符。
需要包含报文标识符的控制报文
控制报文 | 报文标识符字段 |
---|---|
CONNECT | 不需要 |
CONNACK | 不需要 |
PUBLISH | 需要(如果Qos > 0) |
PUBACK | 需要 |
PUBREC | 需要 |
PUBREL | 需要 |
PUBCOMP | 需要 |
SUBSCRIBE | 需要 |
SUBACK | 需要 |
UNSUBSCRIBE | 需要 |
UNSUBACK | 需要 |
PINGREQ | 不需要 |
PINGRESP | 不需要 |
DISCONNECT | 不需要 |
客户端和服务端彼此独立低分配报文标识符,因此客户端、服务端组合使用相同的报文标识符,可以实现并发的消息交换。
4.有效载荷
某些MQTT控制报文在报文的最后部分包含了一个有效载荷,比如对于PUBLISH来说,有效载荷就是应用消息。下表中列出了需要有效载荷的控制报文类型
控制报文 | 有效载荷 |
---|---|
CONNECT | 需要 |
CONNACK | 不需要 |
PUBLISH | 可选 |
PUBACK | 不需要 |
PUBREC | 不需要 |
PUBREL | 不需要 |
PUBCOMP | 不需要 |
SUBSCRIBE | 需要 |
SUBACK | 需要 |
UNSUBSCRIBE | 需要 |
UNSUBACK | 不需要 |
PINGREQ | 不需要 |
PINGRESP | 不需要 |
DISCONNECT | 不需要 |
5 小结
MQTT协议报文的结构由3部分组成,可以简单的理解为:
(1)固定报头:表示这个报文的类型(CONNECTPUBLISH…)
(2)可变报头:Packet ID,也就是 报文的 顺序ID。
(3)有效载荷:应用消息。
最后
以上就是辛勤鲜花为你收集整理的MQTT协议详解及开发教程(四)MQTT协议报文格式前言1.MQTT 控制报文结构2 固定头3. 可变报头4.有效载荷5 小结的全部内容,希望文章能够帮你解决MQTT协议详解及开发教程(四)MQTT协议报文格式前言1.MQTT 控制报文结构2 固定头3. 可变报头4.有效载荷5 小结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复