码迷,mamicode.com
首页 > 其他好文 > 详细

MQTT 协议学习:001-MQTT协议数据包结构

时间:2020-02-03 16:09:06      阅读:400      评论:0      收藏:0      [点我收藏+]

标签:fill   内容   控制   c++   sock   serve   质量   flags   增加   

背景

工作中参与有关调试的时候,发现对于协议帧的解析是比较重要的。

参考:《MQTT协议 -- 消息报文格式》《基于STM32实现MQTT》《MQTT协议从服务端到客户端详解》

MQTT协议数据包结构

技术图片

在MQTT协议中,一个MQTT数据包由:固定头(Fixed header)、可变头(Variable header)、消息体(payload)三部分构成。

  • (1)固定头(Fixed header)。存在于所有MQTT数据包中,表示数据包类型及数据包的分组类标识。
  • (2)可变头(Variable header)。存在于部分MQTT数据包中,数据包类型决定了可变头是否存在及其具体内容。 可变头部不是可选的意思,而是指这部分在有些协议类型中存在,在有些协议中不存在。
  • (3)消息体(Payload)。存在于部分MQTT数据包中,表示客户端收到的真正内容。 与可变头一样,在有些协议类型中有消息内容,有些协议类型中没有消息内容。

MQTT固定头

MQTT协议分很多种类型,如连接,发布,订阅,心跳等。所有类型的MQTT协议中,都必须包含固定头。

固定头包含两部分内容,首字节(字节1)和剩余消息报文长度(1-4字节)。

由于markdown 表示合并表格有技术难度。对于下方有些bit 实际上是 byte1:7~4 是合并的, byte1:3~0是合并的。
可以参考这里,2个表格是等价的。

Bit 7 6 5 4 3 2 1 0
Byte 1 MQTT Control Packet type Flags specific to each MQTT Control Packet type
Byte 2... Remaining Length

协议类型

Byte1的 Bit[7-4]: MQTT Control Packet type,协议类型。总共可以表示16种协议类型,其中0000和1111是保留字段。

报文类型 Bit[7-4]值 数据方向 描述
保留 0000 禁用 保留
CONNECT 0001 Client ---> Server 客户端连接到服务器
CONNACK 0010 Server ---> Client 连接确认
PUBLISH 0011 Client <--> Server 发布消息
PUBACK 0100 Client <--> Server 发不确认
PUBREC 0101 Client <--> Server 消息已接收(QoS2第一阶段)
PUBREL 0110 Client <--> Server 消息释放(QoS2第二阶段)
PUBCOMP 0111 Client <--> Server 发布结束(QoS2第三阶段)
SUBSCRIBE 1000 Client ---> Server 客户端订阅请求
SUBACK 1001 Server ---> Client 服务端订阅确认
UNSUBACRIBE 1010 Client ---> Server 客户端取消订阅
UNSUBACK 1011 Server ---> Client 服务端取消订阅确认
PINGREQ 1100 Client ---> Server 客户端发送心跳
PINGRESP 1101 Server ---> Client 服务端回复心跳
DISCONNECT 1110 Client ---> Server 客户端断开连接请求
保留 1111 禁用 保留

报文类型标志位

Byte1的 Bit[3-0]: Flags specific to each MQTT Control Packet type,字节位用作某些报文类型的标志位。
实际上只有少数报文类型有控制位,如下表。

报文类型 固定头标记 Bit 3 Bit 2 Bit 1 Bit 0
CONNECT 保留 0 0 0 0
CONNACK 保留 0 0 0 0
PUBLISH Used in MQTT 3.1.1 DUP QoS QoS RETAIN
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
UNSUBACRIBE 保留 0 0 1 0
UNSUBACK 保留 0 0 0 0
PINGREQ 保留 0 0 0 0
PINGRESP 保留 0 0 0 0
DISCONNECT 保留 0 0 0 0

当发布PUBLISH消息时,如果DUP字段(bit 3)设置为1,表明这是一条重复消息,否则是第一次发布消息。为了保证消息的可靠性传递,当QoS设置为1时,客户端或服务器发布消息时,需要得到对方的确认(PUBACK),如果一段时间后没收到PUBACK,那么会再次发送当前消息,并将DUP字段标记为1。

QoS用来表明QoS等级,如果Bit 1和Bit 2都为0,表示QoS 0。如果Bit 1为1,表示QoS 1。如果Bit 2为1,表示QoS 2。如果同时将Bit 1和Bit 2都设置成1,那么客户端或服务器认为这是一条非法的消息,会关闭当前连接。

目前Bit[3-0]只在PUBLISH协议中使用有效,并且表中指明了是MQTT 3.1.1版本。对于其它MQTT协议版本,内容可能不同。所有固定头标记为"保留"的协议类型,Bit[3-0]必须保持与表中保持一致,如SUBSCRIBE协议,其Bit 1必须为1。如果接收方接收到非法的消息,会强行关闭当前连接。

剩余长度

剩余长度的计算从理解上是一大难点。注意理解好下面2句加粗的句子。

Remaining Length意思是剩余长度,即可变头(Variable header) + 消息体(payload)的长度。

剩余长度从Byte 2开始,最长可达4字节。即:剩余长度范围是Byte2到Byte5。

计算: 剩余长度 所占用的字节数

MQTT协议规定,byte2(最高到byte5)的bit7(最高位)若为1,则表示还有后续字节存在。

记 N 为 消息报文中的 第n个byte, (2 < N < 5),
如果byte N 的 bit7 是1,那么Byte M (M = N + 1, M < 5 ) 作为剩余长度的一部分,可用于继续计算字节长度;
如果byte N 的 bit7 是0,那么Byte M (M = N + 1, M < 5 ) 就不能看作是剩余长度的一部分计算字节长度。

所以单个字节最大值:01111111,即:0x7F,10进制为127。
MQTT协议最多允许4个字节表示剩余长度。那么最大长度为:0xFF,0xFF,0xFF,0x7F。

计算:剩余长度 所代表长度

消息长度可以简单理解为128进制的数据,4位长度最大可以表示128128128*128Byte=256MB。
注意:长度的计算有些特别,即低位在前,高位在后。以下是消息长度的长度范围:

字节 最小值 最大值
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)

1.2 标识位

位置:Byte 1中bits 3-0。

在不使用标识位的消息类型中,标识位被作为保留位。如果收到无效的标志时,接收端必须关闭网络连接:

(1)DUP:发布消息的副本。用来在保证消息的可靠传输,如果设置为1,则在下面的变长中增加MessageId,并且需要回复确认,以保证消息传输完成,但不能用于检测消息重复发送。

(2)QoS:发布消息的服务质量,即:保证消息传递的次数

?00:最多一次,即:<=1

?01:至少一次,即:>=1

?10:一次,即:=1

?11:预留

(3)RETAIN: 发布保留标识,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它,如果设有那么推送至当前订阅者后释放。 1.3 剩余长度(Remaining Length)

地址:Byte 2。

固定头的第二字节用来保存变长头部和消息体的总大小的,但不是直接保存的。这一字节是可以扩展,其保存机制,前7位用于保存长度,后一部用做标识。当最后一位为1时,表示长度不足,需要使用二个字节继续保存。例如:计算出后面的大小为0

2 MQTT可变头

MQTT数据包中包含一个可变头,它驻位于固定的头和负载之间。可变头的内容因数据包类型而不同,较常的应用是作为包的标识:

很多类型数据包中都包括一个2字节的数据包标识字段,这些类型的包有:PUBLISH (QoS > 0)、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK。

3 Payload消息体

Payload消息体位MQTT数据包的第三部分,包含CONNECT、SUBSCRIBE、SUBACK、UNSUBSCRIBE四种类型的消息:

  • (1)CONNECT,消息体内容主要是:客户端的ClientID、订阅的Topic、Message以及用户名和密码。
  • (2)SUBSCRIBE,消息体内容是一系列的要订阅的主题以及QoS。
  • (3)SUBACK,消息体内容是服务器对于SUBSCRIBE所申请的主题及QoS进行确认和回复。
  • (4)UNSUBSCRIBE,消息体内容是要订阅的主题。

MQTT有C/C++语言和JAVA包实现。需要明确的是,MQTT更适用于设备终端和手机APP socket通信,而不能支持浏览器使用。如果要支持微信浏览器应用,还需要增加类似WebsocketServlet技术给浏览器提供支持,这时MQTT以JS接口进行封装,并被调用完成消息推送。

MQTT 协议学习:001-MQTT协议数据包结构

标签:fill   内容   控制   c++   sock   serve   质量   flags   增加   

原文地址:https://www.cnblogs.com/schips/p/12255552.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!