MQTT协议详解及开发教程(四)MQTT协议报文格式

推荐一款稳定的基于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位无符号值,这些值的定义如下表:

名字报文流动方向描述
Reserved0禁止保留
CONNECT1客户端到服务端客户端请求连接服务端
CONNACK2服务端到客户端连接报文确认
PUBLISH3双向发布消息
PUBACK4双向QoS 1消息发布收到确认
PUBREC5双向发布收到(保证交付第一步)
PUBREL6双向发布释放(保证交付第二步)
PUBCOMP7双向QoS 2消息发布完成
SUBSCRIBE8客户端到服务端客户端订阅请求
SUBACK9服务端到客户端订阅请求报文确认
UNSUBSCRIBE10客户端到服务端客户端取消订阅请求
UNSUBACK11服务端到客户端取消订阅报文确认
PINGREQ12客户端到服务端心跳请求
PINGRESP13服务端到客户端心跳响应
DISCONNECT14客户端到服务端客户端断开连接
Reserved15禁止保留

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,表示 2
128 = 256,
所以本例中的剩余长度编码为 0xC1,0x02,我们去计算的时候是这样:

len = 0xC1&0X7F + 0x02*0x7F // 321

下表中描述了不同字节数表示的剩余长度大小

字节数最小值最大值
10(0x00)127(0x7F)
2128(0x80, 0x01)16383(0xFF,0x7F)
316384(0x80, 0x80, 0x01)2097151(0xFF, 0xFF, 0x7F)
42097152(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)固定报头:表示这个报文的类型(CONNECT\PUBLISH…)
(2)可变报头:Packet ID,也就是 报文的 顺序ID。
(3)有效载荷:应用消息。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页