MQTT协议分析

MQTT

1、概述
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(Publish/Subscribe)模式和客户端服务端架构的轻量级通讯协议,由IBM在1999年发布,目前最新版本为v3.1.1。
在物联网的时代,每一个传感器每一个设备都想接入互联网进行数据交换。MQTT,目前物联网的最主要的协议之一,大部分收费的云平台都是基于MQTT协议,比如机智云,和所有的开放云平台比如中国移动的oneNet、百度的IoT Hub及阿里云的IoT Hub等服务器也都支持MQTT的接入。MQTT协议的实现也非常简单,对带宽的要求不高,对网络链接的可靠性要求也不高,而且协议本身制定了一定的机制来处理突发事件。
MQTT协议构建于TCP/IP协议上,属于应用层协议,因此只要是支持TCP/IP协议栈的地方,都可以使用MQTT。它的设计思想是轻巧、开放、简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(M2M) 以及物联网环境(IoT)。MQTT最大的优点在于可以以极少的代码和有限的带宽,为远程设备提供实时可靠的消息服务。做为一种低开销、低带宽占用的即时通讯协议,MQTT在物联网、小型设备、移动应用等方面有广泛的应用。
MQTT通信协议需要有三个角色:发布者客户端(负责发送消息),代理服务器(负责接收和分发消息),订阅者客户端(负责接收消息)。发布者客户端和订阅者客户端既可以是同一台设备,也可以是不同的设备,只要这台设备可以通过服务器的认证,并且遵循MQTT协议,就可以发布或者订阅消息。
MQTT协议是为大量计算能力有限,且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议,它具有以下主要的几项特性:
1、使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合;
2、对负载内容屏蔽的消息传输;
3、使用 TCP/IP 提供网络连接;
4、提供三种消息发布服务质量:
“至多一次”,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
“至少一次”,确保消息到达,但消息重复可能会发生。
“只有一次”,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。
5、小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量;
6、使用Last Will和Testament特性通知有关各方客户端异常中断的机制;

1.1、术语 Terminology
客户端 Client,使用MQTT的程序或设备。客户端总是通过网络连接到服务端。它可以
1)发布应用消息给其它相关的客户端。
2)订阅以请求接受相关的应用消息。
3)取消订阅以移除接受应用消息的请求。
4)从服务端断开连接。

服务端 Server,一个程序或设备,作为发送消息的客户端和请求订阅的客户端之间的中介。服务端
1)接受来自客户端的网络连接。
2)接受客户端发布的应用消息。
3)处理客户端的订阅和取消订阅请求。
4)转发应用消息给符合条件的已订阅客户端。

订阅 Subscription
订阅包含一个主题过滤器(Topic Filter)和一个最大的服务质量(QoS)等级。订阅与单个会话(Session)关联。会话可以包含多于一个的订阅。会话的每个订阅都有一个不同的主题过滤器。

主题名 Topic Name
附加在应用消息上的一个标签,服务端已知且与订阅匹配。服务端发送应用消息的一个副本给每一个匹配的客户端订阅。

主题过滤器 Topic Filter
订阅中包含的一个表达式,用于表示相关的一个或多个主题。主题过滤器可以使用通配符。

会话 Session
客户端和服务端之间的状态交互。一些会话持续时长与网络连接一样,另一些可以在客户端和服务端的多个连续网络连接间扩展。

控制报文 MQTT Control Packet
通过网络连接发送的信息数据包。MQTT规范定义了十四种不同类型的控制报文,其中一个(PUBLISH报文)用于传输应用消息。

1.2、数据表示 Data representations
二进制位 Bits:字节中的位从0到7。第7位是最高有效位,第0位是最低有效位。
整数数值 Integer data values:整数数值是16位,使用大端序(big-endian,高位字节在低位字节前面)。这意味着一个16位的字在网络上表示为最高有效字节(MSB),后面跟着最低有效字节(LSB)。
UTF-8编码字符串 UTF-8 encoded strings:UTF-8 [RFC3629] 是一个高效的Unicode字符编码格式,可以传送的UTF-8编码的字符串大小有一个限制,不能超过 65535字节。除非另有说明,所有的UTF-8编码字符串的长度都必须在0到65535字节这个范围内。

2、MQTT消息格式
每条MQTT命令消息的消息头都包含一个固定的报头,有些消息会携带一个可变报文头和一个负荷。

表 MQTT控制报文结构
MQTT协议分析
2.1、固定报文头
MQTT固定报文头最少有两个字节,第一字节包含消息类型(Message Type)和QoS级别等标志位。第二字节开始是剩余长度字段,该长度是后面的可变报文头加消息负载的总长度,该字段最多允许四个字节。

表 固定报头格式
MQTT协议分析
2.1.1、MQTT控制报文的类型
固定报文头中的第一个字节包含连接标志(Connect Flags),连接标志用来区分MQTT的消息类型。MQTT协议拥有14种不同的消息类型,可简单分为连接及终止、发布和订阅、QoS 2消息的机制以及各种确认ACK。
表 控制报文的类型
MQTT协议分析
2.1.2、标志 Flag
表 标志位 Flag Bits
MQTT协议分析
注:
DUP1 =控制报文的重复分发标志
QoS2 = PUBLISH报文的服务质量等级
RETAIN3 = PUBLISH报文的保留标志

2.1.3、剩余长度 Remaining Length
剩余长度(Remaining Length)表示当前报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。剩余长度字段使用一个变长度编码方案,对小于128的值它使用单字节编码。更大的值按下面的方式处理。低7位有效位用于编码数据,最高有效位用于指示是否有更多的字节。剩余长度字段单个字节最大值为二进制0111 1111,16进制为0x7F。也就是说,单个字节可以描述的最大长度是127字节。MQTT协议规定,单个字节第八位(最高位)若为1,则表示后续还有字节存在,第八位起“延续位”的作用。
例如,数字64,编码为一个字节,十进制表示为64,十六进制表示为0x40。数字321(65+2128)编码为两个字节,第一个字节为65+128=193(0xC1),第二个字节是2(0x02),表示2128。由于MQTT协议最多只允许使用四个字节表示剩余长度,并且最后一字节最大值只能是0x7F不能是0xFF,所以能发送的最大消息长度是256MB,而不是512MB。

表 长度字段范围
MQTT协议分析
非负整数X使用变长编码方案的算法如下:

do
    encodedByte = X MOD 128
    X = X DIV 128
    // if there are more data to encode, set the top bit of this byte
    if ( X > 0 )
        encodedByte = encodedByte OR 128
    endif
        'output' encodedByte
while ( X > 0 )

MOD是模运算,DIV是整数除法,OR是位操作或(C语言中分别是%,/,|)。

剩余长度字段的解码算法如下:

multiplier = 1
value = 0
do
    encodedByte = 'next byte from stream'
    value += (encodedByte AND 127) * multiplier
    multiplier *= 128
    if (multiplier > 128*128*128)
        throw Error(Malformed Remaining Length)
while ((encodedByte AND 128) != 0)

AND是位操作与(C语言中的&)。
这个算法终止时,value包含的就是剩余长度的值。

2.2、可变报头 Variable header
某些MQTT控制报文包含一个可变报头部分。它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。可变报文头主要包含协议名、协议版本、连接标志(Connect Flags)、心跳间隔时间(Keep Alive timer)、连接返回码(Connect Return Code)、主题名(Topic Name)等。

2.2.1、报文标识符 Packet Identifier
很多控制报文的可变报头部分包含一个两字节的非零报文标识符字段。客户端和服务端彼此独立地分配报文标识符。因此,客户端服务端组合使用相同的报文标识符可以实现并发的消息交换。客户端每次发送一个新的这些类型的报文时都必须分配一个当前未使用的报文标识符。如果一个客户端要重发这个特殊的控制报文,在随后重发那个报文时,它必须使用相同的标识符。当客户端处理完这个报文对应的确认后,这个报文标识符就释放可重用。

表 包含报文标识符的控制报文
MQTT协议分析
2.3、有效载荷 Payload
某些MQTT控制报文在报文的最后部分包含一个有效载荷。对于PUBLISH来说有效载荷就是应用消息。

表 包含有效载荷的控制报文
MQTT协议分析
3、MQTT控制报文消息类型及格式
3.1、CONNECT – 连接服务端
客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文。在一个网络连接上,客户端只能发送一次CONNECT报文。服务端必须将客户端发送的第二个CONNECT报文当作协议违规处理并断开客户端的连接。有效载荷包含一个或多个编码的字段。包括客户端的唯一标识符,Will主题,Will消息,用户名和密码。除了客户端标识之外,其它的字段都是可选的,基于标志位来决定可变报头中是否需要包含这些字段。

3.1.1、固定报头 Fixed header
表 CONNECT报文的固定报头
MQTT协议分析
3.1.2、可变报头 Variable header
CONNECT报文的可变报头按下列次序包含四个字段:协议名(Protocol Name),协议级别(Protocol Level),连接标志(Connect Flags)和保持连接(Keep Alive)。
3.1.2.1、协议名 Protocol Name
表 协议名字节构成
MQTT协议分析

上一篇:313-STM32+Air724UG基本控制篇(自建物联网平台)-加密通信测试-STM32+Air724以SSL单向认证方式连接MQTT服务器(不验证服务器证书)


下一篇:MQTT 协议是个啥?这篇文章告诉你!