MQTT作为目前最主流的物联网协议,大家应该都很熟悉,包括阿里云、百度云等都是通过MQTT协议来实现通讯的,与HTTP一样,其本身都是建立在TCP/IP协议上,本文会详细介绍MQTT报文协议,让大家直观地感受到MQTT报文的结构与内容。
在探究MQTT底层的报文之前,大家还应该对于MQTT本身的工作模式有一个简要直观的了解。首先MQTT是一种低开销、低带宽占用的即时通讯协议,它本身是一种消息发布/订阅的机制实现端与服务器通讯的协议。对于服务器而言,没有订阅的概念;而对于客户端而言,既有发布概念,也有订阅概念,客户端通过发布主题向服务器发布信息,服务器收到信息后根据客户端的发布主题对消息进行处理。而消息的发布又要区分QoS概念,0/1/2分别对应消息传输一次,保证传输一次以及保证仅仅传输一次,这些涉及到服务器与客户端在通讯过程中是否有交互的过程。这几个概念是MQTT主要的几个概念,下面正式去详解MQTT的报文内容。
首先探究MQTT报文内容,是直接使用TCP服务器进行通讯的(不使用MQTT服务器),因为MQTT协议本身是基于TCP协议进行通讯的,所以只要服务器向设备发起的请求连接报文以及订阅报文进行正确的回复,普通的TCP服务器完全可以当做MQTT服务器接收到客户端发布的消息,并且能非常简单地将设备发送的包抓出来,其他手段类似于抓包工具也能实现但是并不能直观帮助我们了解这一过程。
拿一个亿佰特的4G-DTU设备举例(其他设备也是一样的),由于MQTT本身要配置三元组,我们将设备配置成标准MQTT工作模式,三元组按照下面的参数配置,然后目标地址与端口直接填写我们TCP服务器的地址与端口,订阅与发布都勾选并且都按照如下进行配置,然后观察我们TCP服务器上交互的信息。
67feb53ba98149fcbd8d2ccc5436d3da~noop.image?_iz=58558&from=article.jpg

以下为TCP服务器端交互的信息:
e7101b4a9be6422fb0eb0b1a1de023ee~noop.image?_iz=58558&from=article.jpg

连接MQTT第一步是请求TCP服务器连接,这一步由协议栈直接完成不需要管,然后客户端会发送请求MQTT服务器连接报文,也就是上面的第一条消息:
第一个byte为0x10,其为MQTT协议固定头部分,此byte的8个bit位分别代表了不同的意义,高四位与低四位的值分别代表的意义也贴在了下方:
9c8b92c3df104ead9b3aa1ee4fea4757~noop.image?_iz=58558&from=article.jpg

高四位信息:
3c057f2af53a4d7a88ea08f9660708b9~noop.image?_iz=58558&from=article.jpg

低四位信息:
653e979fa8264185994eb9a961b2dd60~noop.image?_iz=58558&from=article.jpg

以上就是固定头部分的内容,常见的固定头以及其意义如下:
d00128d316a140e5a3228f994e4564d4~noop.image?_iz=58558&from=article.jpg

这里就能直观地理解MQTT交互过程中的几个交互报文的头部了,先是0x10为首的请求MQTT连接报文;其次是0x20为首的服务器响应连接的报文;然后是0x82为首的设备订阅请求报文;接着是0x90为首的订阅请求回复。至此完成了设备连接MQTT服务器并且订阅成功的过程。最后是设备发布的报文,以0x30为首。
MQTT通讯报文的第二个字节指示的是剩余字段的长度,比如请求连接报文第二个字节值为0x1F代表后面的一个字节为剩余长度,这个剩余长度最大占用4个字节,每个字节的低七位是编码数据,而最高位代表后面有没有更多字节位,表示后续有没有更多的字节为代表剩余字节数。而剩余的包括MQTT三元组信息,是可以在请求连接报文中看到的(0x31 0x31 0x31 就代表Client ID ,其前面的0x03代表Client ID 的长度),而发布topic,可以在客户端发布的报文中看到。
这些就是MQTT报文的详情,去了解底层的报文结构有助于我们更好地掌控此协议的用法以及排查问题。

来源:亿佰特物联网实验室