初识MQTT协议

最近在看MQTT协议相关的内容,先整理收集的一些信息,以及自己的一些理解,如有错误之处,敬请纠正,有不清楚的地方,也希望能够和大家一起讨论,探讨 本篇文章,简述MQTT历史,产生所要解决的问题,以及协议的基础格式。

 

前言

MQTT协议是一个简单的中心辐射型系统:传感器、应用和设备之间的通信是通过*代理端运行的数据中心服务实现的。其精简低带宽的特性使得它能够适用于很多应用,比如家庭自动化:包括供暖、通风、空调(HVAC)、照明、智能设备和安全等方面都采用了MQTT协议。

初识MQTT协议

 

1

浅谈历史

MQTT协议由Andy Stanford-Clark(IBM)和Arlen Nipper(Arcom,现为Cirrus Link)于1999年发明。他们需要一种协议,以最小化电池损耗和最小带宽,通过卫星与石油道管连接。 发明之初为协议规定了几个要求:

 

  1. 实施简单

  2. 提供服务质量的数据传输

  3. 轻巧和带宽高效

  4. 数据不可知

  5. 持续的会话意识

 

2

协议格式

MQTT协议控制报文的格式包含以下三个部分,以固定报头,可变报头和有效载荷,其中固定报文头是所有的控制报文都有, 可变报头和有效载荷都是部分控制报文包含。

 

固定报头

固定报头是两个字节组成,其具体的格式如下所示:

初识MQTT协议

 

控制报文类型

第一个字节的二进制位7-4无符号整数表示控制报文的类型,具体类型对应的值为:

初识MQTT协议

备注: 其中预留值15已经在MQTT5中使用到AUTH中了。

 

标志

第一个字节的二进制位3-0包含每个MQTT控制报文类型特定的标志, 控制报文中的标志为必须按照如下表格进行设置,如果设置有问题,则接收者必须断开连接。

 

初识MQTT协议

备注:从协议规范看出,目前只有PUBLISH的标志位是使用的,其他控制报文都是预留状态,但是必须保持上述表格的形式。

 

剩余长度

第二个字节表示当前报文剩余部分的字节数,包括可变报头和有效载荷。剩余长度不包括用于编码剩余长度字段本身的字节数。剩余长度字段使用一个变长度编码方案,对小于128的值使用单字节编码,超过128的值,最高有效未用于指示是否有更多的字节,因此每个字节可以编码128个数值和一个延续位,剩余长度字段最大4个字节。 举例:十进制64被编码为一个字节,十六进制表示为Ox40。十进制数字321编码为两个字节,最低有效位在前,第一个字节65+128=193,第二个字节为2。 剩余长度最大为256M的报文,而且报文是不支持分包处理的,所以MQTT协议并不适合一些数据量特别大的场景,比如视频直播等数据包比较大的场景。

 

可变报头

可变报头介于固定报头和有效载荷中间。不同的控制报文有着不同的可变报头,其中PacketId是一个在多个控制报文中存在一个报文。 PacketId包含两个字节,现在包含该字段的控制报文有,PUBLISH(Qos>0), PUBACK, PUBREC, PUBREL,PUBCOMP,SUBSCRIBE,SUBACK, UNSUBSCRIBE, UNSUBACK。

具体包含情况如下:

 

初识MQTT协议

注意事项

  • PUBLISH Qos0的报文是不能又packetId的。

  • 有些对应的控制报文中的packetId必须和与该控制报文绑定的其它控制报文保持一直,例如PUBLISH Qos1对应的是PUBACK,PUBLISH Qos2对应的PUBCOMP。

  • 发送者和接收者是分开维护各自的packetId,所以会出现交互双方出现相同packetId的两个不同的控制报文。

  • 关于不能有packetId的控制报文,可能是由于packetId是可以复用的,没有办法确认可以复用的场景不能使用报文,比如Qos0的PUBLISH报文,由于没有回应,所以发送者无法得知packetId何时可以释放复用,故不允许存在该字段。

 

有效载荷

有效载荷即为应用消息。 目前MQTT3.1.1中包含如下的控制报文CONNECT, CONNACK, PUBLISH, PUBACK,PUBREC, PUBREL, PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE,UNSUBACK,PINGREQ,PINGRESP,DISCONNECT的协议,关于这些协议的具体格式,使用场景等将在后续的文章中给出解释。

 

3

总结

MQTT是二进制的协议,控制字段是精确到Bit级别的,单纯这一点就足以为其在物联网领域占据一席之地。MQTT是不支持分包等机制,并不适宜一些数据包特别大的应用场景。

初识MQTT协议
上一篇:Roads in the Kingdom CodeForces - 835F (直径)


下一篇:QlikView 中给字段赋值