MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
MQTT协议通常作为连接云服务器的通道,比如阿里云、京东云等厂商用就将mqtt作为连接其云服务器的底层通信协议。为了保证数据的安全,通常还需要在mqtt上面加上一层安全传输协议(SSL)。
MQTT的主要角色:
MQTT Broker 也称为 MQTT 消息服务器,它可以是运行了 MQTT 消息服务器软件的一台服务器或一个服务器集群。MQTT Broker 负责接收来自客户端的网络连接,并处理客户端的订阅/取消订阅(Subscribe/Unsubscribe)、消息发布(Publish)请求,同时也会将客户端发布的消息转发给其他订阅者。broker在转发消息的同时也可以主动下发消息给订阅了相应主题的订阅者。
MQTT客户端(Client)既可以发布消息,也可以订阅消息,所以MQTT客户端的身份可以是消息发布者(Publisher),也可以是消息订阅者(subscriber)。同一个客户端也可以订阅自己发布的消息。
MQTT的这种通信模型类似于古老的邮局,订阅者和发布者相当于订阅报纸的用户,服务器就相当于邮局,邮局负责将用户订阅的报纸、杂志送到用户手里,用户也可以通过邮局寄送(发布)邮件到其他用户。
MQTT数据包结构由三部分组成:
每一个MQTT消息都包含固定报头。
MQTT Control Packet type一共4bit,指明了MQTT数据包的类型,其定义如下:
Name | Value | Direction of flow | Description |
---|---|---|---|
Reserved | 0 | Forbidden | Reserved |
CONNECT | 1 | Client to Server | Client request to connect to Server |
CONNACK | 2 | Server to Client | Connect acknowledgment |
PUBLISH | 3 | Client to Server or Server to Client | Publish message |
PUBACK | 4 | Client to Server or Server to Client | Publish acknowledgment |
PUBREC | 5 | Client to Server or Server to Client | Publish received (assured delivery part 1) |
PUBREL | 6 | Client to Server or Server to Client | Publish release (assured delivery part 2) |
PUBCOMP | 7 | Client to Server or Server to Client | Publish complete (assured delivery part 3) |
SUBSCRIBE | 8 | Client to Server | Client subscribe request |
SUBACK | 9 | Server to Client | Subscribe acknowledgment |
UNSUBSCRIBE | 10 | Client to Server | Unsubscribe request |
UNSUBACK | 11 | Server to Client | Unsubscribe acknowledgment |
PINGREQ | 12 | Client to Server | PING request |
PINGRESP | 13 | Server to Client | PING response |
DISCONNECT | 14 | Client to Server | Client is disconnecting |
Reserved | 15 | Forbidden | Reserved |
从表格中可以看出,MQTT消息的发布、订阅,以及MQTT连接的建立、心跳的保持都是由客户端主动发起的,服务器端只负责响应这些消息。
Bit3-Bit0通常在发布消息(Publish)的过程中使用,表示MQTT的消息质量(Qos)、Dup、Retain特征。
1. DUP Flag
如果DUP标识被设置为0,标识这是服务端或客户端第一次尝试发送MQTT PUBLISH包。如果DUP标识被设置为1,标识这可能是在重复发送早前尝试发送过的数据包。所有QoS为0的消息DUP标识必须也设置为0。
2. Qos
Qos表示发布消息的质量,0表示来自客户端的消息至最多达一次,1表示消息最少到达一次,2表示消息只到达1次。
3. Retain
如果客户端Publish数据包中的Retain位设置为1,服务器会将这条消息存储,并在下一次客户端订阅该消息时自动将该topic发送给订阅者。如果Publish数据包的Retain位设置为0,客户端在重新订阅该消息的时候,服务器不会主动发送数据给订阅者。
我们可以使用Mqtt.fx做个测试,首先连接一个免费的broker(broker.hivemq.com),然后向Broker Publish一条主题为TopicA的消息,Qos设置为1,Retain设置为1,点击发布。之后我们断开并重新连接Broker,分别订阅主题TopicA和主题TopicB,这时我们会发现TopicA会接收到我们上次发送的那条消息,而TopicB没有任何消息到达。
MQTT客户端在连接服务器的时候(CONNECT)需要指明是否清除回话(Clean Session)和遗嘱消息(Will Flag)。在Connect过程中,这两个字段都位于第8个字节:
Clean Session为0表示不清除上一次的会话信息,这种情况下服务器会保存上一次和客户端的连接信息。比如当连接重新建立之后,服务器会发送上一次没有收到PUBACK的消息到客户端。
Clean Session为1表示清除上一次的会话信息,每一重新连接都会建立一个新的Session。
客户端会话状态的构成:
服务端会话状态的构成:
Will Flag表示是否设置遗嘱消息,当客户端和服务器之间因为某些原因正常或者异常断开时,服务器必须发布响应的遗嘱消息到客户端,如果客户端在发送Connect请求时删除了遗嘱消息,则服务器不需要发送遗嘱消息。
遗嘱消息对应的Topic也包含Qos、Retain等字段,Qos的同样表示消息的质量等级,Retain表示服务器在发布遗嘱消息后是否需要保留。
详细内容请参考MQTT协议3.1.2.5章的内容。
举个例子,在客户端 A 进行连接时候,遗嘱消息设定为”offline“,客户端 B 订阅这个遗嘱主题。当 A 异常断开时,客户端 B 会收到这个”offline“的遗嘱消息,从而知道客户端 A 离线了。
下图抓取了MQTT的CONNECT、CONNACK、PING、PINGREQ、PINGRESP、PUBLISH、DISCONNECT的过程。
wireshark是可以直接解析mqtt协议的,我们点击Publish message一栏,可以得到如下信息
官网地址:http://mqtt.org/
MQTTv3.1.1下载地址:https://os.mbed.com/teams/mqtt/code/MQTTPacket/