MQTT协议--消息报⽂格式
虽然学习协议是枯燥的,但是熟悉协议本⾝却是很重要的事情。如果能把其细节弄清楚,并且配合⼀些实验来学习,就不会那么枯燥了。
消息报⽂格式
MQTT协议是应⽤层协议,需要借助TCP/IP协议进⾏传输,类似HTTP协议。MQTT协议也有⾃⼰的格式,如下表:
[ Fixed Header | Variable Header | Payload]
Fixed Header: 固定头部,MQTT协议分很多种类型,如连接,发布,订阅,⼼跳等。其中固定头是必须的,所有类型的MQTT协议中,都必须包含固定头。
资本主义是什么意思Variable Header:可变头部,可变头部不是可选的意思,⽽是指这部分在有些协议类型中存在,在有些协议中不存在。
Payload:消息载体,就是消息内容。与可变头⼀样,在有些协议类型中有消息内容,有些协议类型中没有消息内容。
固定头
固定头包含两部分内容,⾸字节(字节1)和剩余消息报⽂长度(1-4字节)。
Bit76543210
Byte 1MQTT Control Packet type Flags specific to each MQTT Control Packet type Remaining Length
为了避免翻译不准确,这⾥都使⽤官⽅的原始术语。其中MQTT Control Packet type可以简单理解为字节位Bit[7-4]⽤于确定报⽂类型。Flags specific to each MQTT Control Packet type意思是字节位Bit[3-0]⽤作某些报⽂的特殊标记。
⾸字节
⾸字节⽤于表⽰MQTT消息的报⽂类型以及某些类型的控制标记,如上图。⾼4位(bit7~bit4)表⽰协议类型,总共可以表⽰16种协议类型,其中0000和1111是保留字段。MQTT消息报⽂类型如下。
报⽂类型字段值数据⽅向描述
保留0禁⽤保留
CONNECT1Client ---> Server客户端连接到服务器
CONNACK2Server ---> Client连接确认
PUBLISH3Client <--> Server发布消息
PUBACK4Client <--> Server发不确认
微信励志网名
PUBREC5Client <--> Server消息已接收(QoS2第⼀阶段)
PUBREL6Client <--> Server消息释放(QoS2第⼆阶段)
PUBCOMP7Client <--> Server发布结束(QoS2第三阶段)
SUBSCRIBE8Client ---> Server客户端订阅请求
SUBACK9Server ---> Client服务端订阅确认
UNSUBACRIBE10Client ---> Server客户端取消订阅
UNSUBACK11Server ---> Client服务端取消订阅确认
报⽂类型字段值数据⽅向描述
PINGREQ12Client ---> Server客户端发送⼼跳
PINGRESP13Server ---> Client服务端回复⼼跳
DISCONNECT14Client ---> Server客户端断开连接请求
保留15禁⽤保留
⾸字节的低4位(bit3~bit0)⽤来表⽰某些报⽂类型的控制字段,实际上只有少数报⽂类型有控制位,如下图。
报⽂类型固定头标记Bit 3Bit 2Bit 1Bit 0 CONNECT保留0000
让人开心的句子
CONNACK保留0000
PUBLISH Ud in MQTT 3.1.1DUP QoS QoS RETAIN PUBACK保留0000
PUBREC保留0000
PUBREL保留0010
PUBCOMP保留0000 SUBSCRIBE保留0010
SUBACK保留0000 UNSUBACRIBE保留0010
UNSUBACK保留0000
老是咳嗽PINGREQ保留0000
PINGRESP保留0000 DISCONNECT保留0000
当发布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。如果接收⽅接收到⾮法的消息,会强⾏关闭当前连接。
雷蝎Re m aining L e ng th
Remaining Length意思是剩余长度,即Variable Header + Payload的长度。剩余长度从Byte 2开始,最长可达4字节。所以剩余长度范围是Byte[2-5]。那么怎样确定其长度到底是1还是4呢,这取决于字节的最⾼位Bit 7(默认都是⾼字节在前),如果这个值是1,那么就继续计算字节长度,如果是0,那么就不再计算字节长度。
灶王爷的来历消息长度可以简单理解为128进制的数据,4位长度最⼤可以表⽰128*128*128*128Byte=256MB。但是这个长度的计算有些特别,就是低位在前,⾼位在后(因为正常的表⽰⽅法是⾼位在前,低位在后),字节最⾼位Bit7⽤于标记是否需要继续计算消息长度。以下是消息长度的长度范围:
字节最⼩值最⼤值
10(0x00)127(0x7F)
2128 (0x80, 0x01)16 383 (0xFF, 0x7F)
316 384 (0x80, 0x80, 0x01) 2 097 151 (0xFF, 0xFF, 0x7F)
夏光庭
4 2 097 152 (0x80, 0x80, 0x80, 0x01)268 43
5 455 (0xFF, 0xFF, 0xFF, 0x7F)
稍微注意⼀下,0x80=1000 0000,不是 1000。刚开始以为是1000,所以就没明⽩。
举个例⼦。
消息假设长度是[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]这样的消息长度,那么接收⽅认为这是⼀条⾮法的消息。
Variable Header
Variable Header的意思是可变化的消息头部。有些报⽂类型包含可变头部,如PUBLISH,SUBSCRIBE,CONNECT等等。可变头部在固定头部和消息内容之间,其内容根据报⽂类型不同⽽不同。
Packet Identifier(消息ID)是⼀种常见的可变头部,⼀个消息ID包含2字节,⾼字节在前,低字节在后。包含Packet Identifier的协议类型包括:报⽂类型包含可变头
植物生长变化PUBLISH YES(QoS > 0)
PUBACK YES
PUBREC YES
PUBREL YES
PUBCOMP YES