MQTTv5.0协议详解

一、MQTT协议具体是什么

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),基于TCP/IP的长连接。MQTT是机器对机器(M2M)/物联网(IoT)连接协议,发布/订阅模式,是专为受限设备和低带宽、高延迟、不可靠网络而设计。作为一种低开销、低时延、低带宽占用的即时通讯协议,MQTT在物联网、小型设备、移动应用等方面有广泛的应用。

目前最新版本为:v5.0,在v3.1.1版本的基础上增加了会话/消息延时功能、原因码、主题别名、in-flight流控、属性、共享订阅等功能,增加了用于增强认证的AUTH报文。

二、MQTT协议数据格式

每条MQTT消息最多由三部分组成,始终排列为(固定的报头 | 可变包头 | 有效负荷),如下所示:

固定报头(Fixed Header),存在于所有MQTT控制数据包中
可变报头(Variable Header),存在于某些MQTT控制数据包中

有效负载(Payload),存在于某些MQTT控制数据包中

1、固定报头(Fixed Header),以Connect连接为例说明

MQTT固定报头最少2个字节,第一个字节包含MQTT控制报文类型控制报文类型的【标志位】;第二个字节开始是剩余长度字段,该长度是后面的【可变报头】和【有效负载】的总长度,该字段最多允许4个字节。

位(Bit) 7 6 5 4 3 2 1 0
第一字节(byte) MQTT控制报文类型 控制报文类型的标志位(目前只在Publish协议中使用)
0 0 0 1 0 0 0 0
第二字节(byte 2)...... 剩余长度:可变报头和有效负载的总长度(最长可达4字

1.1 MQTT控制报文类型(第1字节的7~4,4位无符号值):

名称 描述
Reserved 0(0000) 预留
Connect 1(0001) 客户端请求连接服务端
ConnectAck 2(0010) 服务端确认连接建立
Publish 3(0011) 发布消息请求
PublishAck 4(0100) 发布消息确认
PubRec 5(0101) 发布消息收到
PubRel 6(0110) 发布消息释放
PubComp 7(0111) 发布消息完成
Subscribe 8(1000) 订阅消息请求
SubAck 9(1001) 订阅消息确认
UnSubscribe 10(1010) 取消订阅请求
UnSubAck 11(1011) 取消订阅确认
PingReq 12(1100) 客户端发送Ping命令(心跳包)
PingResp 13(1101) Ping命令应答
Disconnect 14(1110) 断开连接

Reserved

Auth

15(1111)

保留(v3.1.1)

认证交换(v5.0)

1.2 标志位(第1字节,二进制位3~0,4位无符号值):

MQTT控制包 标志位 3位 2位 1位 0位
Connect 预留 0 0 0 0
ConnAck 预留 0 0 0 0
Publish MQTT v3.1.1和v5.0中使用 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
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
Auth 预留 0 0 0 0

注:此处的报文不能转化为十进制计算

例:0100表示,0:当前消息第一次发送,10消息质量为2,Retain标志位0

DUP:重复发送Publish数据包次数

Qos:消息质量

Retain:Publish消息保留标志

注:由上表可以看出标志位目前只在Publish协议中使用

 1.3 剩余长度:

如何确定其长度到底是1还是4呢,这取决于字节的最高位Bit 7(默认都是高字节在前),MQTT协议规定,如果这个值是1,那么就继续计算字节长度,如果是0,那么就不再计算字节长度。即Bit7起“延续位”作用。

由于MQTT协议最多只允许使用四个字节表示剩余长度,并且最后一字节最大值只能是0x7F不能是0xFF,所以能发送的最大消息长度是128*128*128*128Byte / 1024 / 1024 = 256MB,而不是512MB。

举例如下:

消息假设长度是[0X60],其二进制是01100000,字节最高位Bit7(从左边起第0位)是0,所以不需要继续往后计算。那么消息长度就是0X60,十进制数是96。

如果消息长度是[0XC1, 0XC2, 0X33],那么他们的二进制分别如下,

0xC1=1100 0001

0xC2=1100 0010

0x33=0011 0011,

第一字节最高位是1,那么需要继续向后计算,去掉标记位(0xC1%128),得到100 0001=41

第二字节最高位是1,那么需要继续向后计算,去掉标记位(0xC2%128),得到100 0010=42

第三字节最高位是0,不需要向后计算,其结果就是0x33=51

因为低位在前,高位在后,那么长度计算为Length=41 + 42*128 + 51*128*128=841001 B = 821KB

需要注意的是,消息长度=可变头部长度+消息内容长度。不包括首字节和消息长度本身,如果消息长度为5,那么说明这条消息后边还有5字节,整条消息长度为7(首字节+1位长度字节+5)。

另外如果消息长度为4字节,最后一位不能超过0X7F=127,因为如果超出这个值,其最高位Bit7是1,还需要往后计算,这与消息最大长度为4字节矛盾。所以如果出现[0XFF, 0XFF, 0XFF, 0XFF]这样的消息长度,那么接收方认为这是一条非法的消息。

2、可变报头(Variable Header),以Connect连接为例说明

某些类型的MQTT控制包包含可变报头组件。它位于固定标题和有效负载之间。可变报头的内容取决于数据包类型。可变报头的数据包标识符字段在几种数据包类型中很常见。可变报头主要包含协议名、协议版本、连接标志(Connect Flags)、心跳间隔时间(Keep Alive )。

2.1、协议名称,在可变报头中占用前6字节

 

描述

7

6

5

4

3

2

1

0

协议名称

字节1

长度MSB(0)

0

0

0

0

0

0

0

0

字节2

长度LSB(4)

0

0

0

0

0

1

0

0

字节3

'M'

0

1

0

0

1

1

0

1

字节4

'Q'

0

1

0

1

0

0

0

1

字节5

'T'

0

1

0

1

0

1

0

0

字节6

'T'

0

1

0

1

0

1

0

0

协议名称是UTF-8编码的字符串,代表协议名称“ MQTT”,大写。

2.2、协议版本,在可变报头中占用第7个字节

 


描述

7

6

5

4

3

2

1

0

协议等级

字节7

版本(5)

0

0

0

0

0

1

0

1

一个字节的无符号值,表示客户端使用的协议的修订级别。

协议版本5.0的“协议版本”字段的值为5(0x05)。

协议版本3.1.1的“协议级别”字段的值为4(0x04)

2.3、连接标志,在可变报头中占用第8个字节

7

6

5

4

3

2

1

0

 

用户名标志

密码标志

Will Retain

Will  QoS

Will  Flag

Clean Session(v3.1.1)

Clean Start(v5.0)

已预留

字节8

X

X

X

X

X

X

X

0

2.3.1、Clean Start(连接标志的位1)

如果在Clean Start设置为1的情况下收到CONNECT数据包,则客户端和服务器务必丢弃任何现有的会话并开始新的会话

如果接收到的CONNECT数据包的Clean Start设置为0,并且有一个与客户端标识符相关联的会话,则服务器务必根据现有会话 状态恢复与客户端的通信。如果接收到的CONNECT数据包的Clean Start设置为0,并且没有与客户端标识符关联的会话,则服务器必须创建一个新的会话 。

 2.3.2、Will  Flag(连接标志的位2)

如果为1表示开启遗嘱通知,

发布遗嘱消息的情况包括但不限于:

  • 服务器检测到I / O错误或网络故障。
  • 客户端在保持活动时间内无法通信。
  • 客户端关闭网络连接,而无需先发送原因码为0x00(正常断开连接)的DISCONNECT数据包。
  • 服务器在没有首先收到原因码为0x00(正常断开连接)的DISCONNECT数据包的情况下关闭了网络连接。

2.3.3、Will Qos(连接标志的位3和位4)

这两位指定发布遗嘱消息时要使用的QoS级别。

如果将Will Flag设置为0,则Will QoS必须设置为0 (0x00)。

如果将Will Flag设置为1,则Will QoS的值可以为0(0x00),1(0x01)或2(0x02)。 值3(0x03)是格式错误的数据包。

2.3.4 Will Retain 消息保留(连接标志的位5)

该位指定在发布遗嘱消息时是否保留该遗嘱消息。

如果遗嘱标志设置为0,则遗嘱保留必须设置为0。如果将Will Flag设置为1并将Will Retain设置为0,则服务器必须将Will消息发布为非保留消息。如果将Will Flag设置为1并将Will Retain设置为1,则服务器必须发布Will消息作为保留消息。

2.3.5 Password Flag 密码标志 (连接标志的位6)

如果密码标志设置为0,则有效负载 中绝对不能存在密码。 如果密码标志设置为1,则有效负载中必须存在密码。

该协议的该版本允许发送不带用户名的密码,而MQTT v3.1.1则不允许。这反映出密码通常用于密码而不是密码。

2.3.6 UserName Flag 用户名标志 (连接标志的位7)

如果用户名标志设置为0,则有效载荷中不得存在用户名。 如果用户名标志设置为1,则用户名必须出现在有效负载。

2.4、 Keep Alive 保活机制,在可变报头中占用第9和10字节

7

6

5

4

3

2

1

0

字节9

Keep Alive MSB

字节10

Keep Alive LSB

Keep Alive是两个字节的整数,它是一个以秒为单位的时间间隔。它是客户端完成传输一个MQTT控制数据包的时间点与它开始发送下一个MQTT控制数据点的时间之间允许的最大时间间隔。客户有责任确保发送的MQTT控制包之间的间隔不超过Keep Alive值。如果Keep Alive不为零且在没有发送任何其他MQTT控制包的情况下,客户端必须发送PINGREQ包,相应的,服务器会返回一个PINGRESP消息进行确认。如果服务器在一个半(1.5)心跳间隔时间周期内没有收到来自客户端的消息,就会断开与客户端的连接。心跳间隔时间最大值大约可以设置为18个小时,0值意味着客户端不断开。

3、有效负载(Payload)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章