MQTT,目前物联网的最主要的协议之一,基本上所有的IOT云平台都使用了MQTT,比如机智云,中国移动的oneNet、百度的云平台、阿里物联网云平台。虽然MQTT很火,但是目前对MQTT的资料确实很少,尤其是在如何移植到嵌入式上来。大部分的平台商的做法都是跟模块商合作把MQTT协议集成到WiFi模块跟GPRS模块里面,捆绑一并销售,不让用户过多的了解物联网最核心的东西。还没有深入去了解MQTT协议之前,总觉的这个东西很复杂,毕竟之前一直想深入,一直也没有时间去仔细琢磨这个东西。随时自己对物联网的不断探索,越来越了解整个物联网的架构,对MQTT了解也越来越深入。
在MQTT
协议中,一个MQTT
数据包由:固定头(Fixed header)
、 可变头(Variable header)
、 消息体(payload)
三部分构成。协议地址:http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html
1、MQTT
数据包结构
-
固定头(Fixed header)
,存在于所有MQTT
数据包中,表示数据包类型及数据包的分组类标识 -
可变头(Variable header)
,存在于部分MQTT
数据包中,数据包类型决定了可变头是否存在及其具体内容 -
消息体(Payload)
,存在于部分MQTT
数据包中,表示客户端收到的具体内容
2、MQTT
固定头
固定头
存在于所有MQTT
数据包中,其结构如下:
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
byte 1 |
| 不同类型 | ||||||
byte 2… | 剩余长度 |
1)MQTT
数据包类型
byte 1,位置: bits 7-4。
相于一个4位的无符号值,类型如下:
名称 | 值 | 流方向 | 描述 |
Reserved (0000xxxx) | 0 | 不可用 | 保留位 |
CONNECT (0001xxxx) | 1 | 客户端到服务器 | 客户端请求连接到服务器 |
CONNACK (0010xxxx) | 2 | 服务器到客户端 | 连接确认 |
PUBLISH (0011xxxx) | 3 | 双向 | 发布消息 |
PUBACK (0100xxxx) | 4 | 双向 | 发布确认 |
PUBREC (0101xxxx) | 5 | 双向 | 发布收到(保证第1部分到达) |
PUBREL (0110xxxx) | 6 | 双赂 | 发布释放(保证第2部分到达) |
PUBCOMP (0111xxxx) | 7 | 双向 | 发布完成(保证第3部分到达) |
SUBSCRIBE (1000xxxx) | 8 | 客户端到服务器 | 客户端请求订阅 |
SUBACK (1001xxxx) | 9 | 服务器到客户端 | 订阅确认 |
UNSUBSCRIBE(1010xxxx) | 10 | 客户端到服务器 | 请求取消订阅 |
UNSUBACK (1011xxxx) | 11 | 服务器到客户端 | 取消订阅确认 |
PINGREQ (1100xxxx) | 12 | 客户端到服务器 | PING请求 |
PINGRESP (1101xxxx) | 13 | 服务器到客户端 | PING应答 |
DISCONNECT (1110xxxx) | 14 | 客户端到服务器 | 中断连接 |
Reserved (1111xxxx) | 15 | 不可用 | 保留位 |
标识位
byte 1 位置:bits 3-0。
在不使用标识位的消息类型中,标识位被做为保留位。如果收到无效的标志时,接收端必须关闭网络连接:
数据包 | 标识位 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
CONNECT | 保留位 | 0 | 0 | 0 | 0 |
CONNACK | 保留位 | 0 | 0 | 0 | 0 |
PUBLISH | MQTT 3.1.1使用 | DUP1 | QoS2 | QoS2 | RETAIN3 |
PUBACK | 保留位 | 0 | 0 | 0 | 0 |
PUBREC | 保留位 | 0 | 0 | 0 | 0 |
PUBREL | 保留位 | 0 | 0 | 0 | 0 |
PUBCOMP | 保留位 | 0 | 0 | 0 | 0 |
SUBSCRIBE | 保留位 | 0 | 0 | 0 | 0 |
SUBACK | 保留位 | 0 | 0 | 0 | 0 |
UNSUBSCRIBE | 保留位 | 0 | 0 | 0 | 0 |
UNSUBACK | 保留位 | 0 | 0 | 0 | 0 |
PINGREQ | 保留位 | 0 | 0 | 0 | 0 |
PINGRESP | 保留位 | 0 | 0 | 0 | 0 |
DISCONNECT | 保留位 | 0 | 0 | 0 | 0 |
DUP
:发布消息的副本。用来在保证消息的可靠传输,如果设置为 1,则在下面的变长中增加MessageId,并且需要回复确认,以保证消息传输完成,但不能用于检测消息重复发送。QoS
:发布消息的服务质量,即:保证消息传递的次数
00
:最多一次,即:<=101
:至少一次,即:>=110
:一次,即:=111
:预留
RETAIN
: 发布保留标识,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它,如果设有那么推送至当前订阅者后释放。
2)剩余长度(Remaining Length)
位置:byte 2(从byte 2,最大可至byte 5)
该字段表示当前消息的剩余内容的字节数,包括可变头部和有效载荷的数据。
该字段本身的字节数是根据可变头部和有效载荷的长度不同而变化的。该可变长度编码方案如下:每个字节的低7位(7-0位)编码剩余长度的数据,第8位表示后面是否还有编码剩余长度的字节。即每个字节编码128个值和一个“延续位”。所以只用一个字节时,最大只可表示127字节的长度。
举例如下,十进制数字64只需用1个字节来编码,即0x40。 十进制数字321(=65 + 2x128)则需要用2个字节来编码,其中第1个字节为1100 0001,该字节的低7位表示65,第8位表示后面还有字节;第2个字节为0000 0010,表示2x128。
协议限制该字段最大为4个字节,这允许应用程序发送的最大消息长度为268435455(256MB),即0xFF,0xFF,0xFF,0x7F。
下表给出了增加该字段的字节数时相应可表示的剩余长度值。
3、 MQTT
可变头
MQTT
数据包中包含一个可变头,它驻位于固定的头和负载之间。可变头的内容因数据包类型而不同,较常的应用是做为包的标识:
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
byte 1 | 包标签符(MSB) | |||||||
byte 2… | 包标签符(LSB) |
很多类型数据包中都包括一个2字节的数据包标识字段,这些类型的包有:PUBLISH (QoS > 0)、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK
4、 Payload
消息体
Payload
消息体位MQTT
数据包的第三部分,CONNECT、SUBSCRIBE、SUBACK、UNSUBSCRIBE四种类型的消息 有消息体:
-
CONNECT
,消息体内容主要是:客户端的ClientID、订阅的Topic、Message以及用户名和密码。 -
SUBSCRIBE
,消息体内容是一系列的要订阅的主题以及QoS
。 -
SUBACK
,消息体内容是服务器对于SUBSCRIBE
所申请的主题及QoS
进行确认和回复。 -
UNSUBSCRIBE
,消息体内容是要订阅的主题。