第一章:MQTT介绍
1.1.定义
MQTT(Message Queuing Telemetry Transport)是一种轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境。它在物联网应用中广受欢迎,能够实现传感器、执行器和其它设备之间的高效通信 。 简单的说客户端只需要订阅这个主题,当有其他客户端向这个主题发布消息时,这个客户端就可以收到这条消息 。
1.2.特点
MQTT 所具有的适用于物联网特定需求的特点和功能,使其成为物联网领域最佳的协议之一。它的主要特点包括:
-
轻量级:物联网设备通常在处理能力、内存和能耗方面受到限制。MQTT 开销低、报文小的特点使其非常适合这些设备,因为它消耗更少的资源,即使在有限的能力下也能实现高效的通信。
-
可靠:物联网网络常常面临高延迟或连接不稳定的情况。MQTT 支持多种 QoS 等级、会话感知和持久连接,即使在困难的条件下也能保证消息的可靠传递,使其非常适合物联网应用。
-
安全通信:安全对于物联网网络至关重要,因为其经常涉及敏感数据的传输。为确保数据在传输过程中的机密性,MQTT 提供传输层安全(TLS)和安全套接层(SSL)加密功能。此外,MQTT 还通过用户名/密码凭证或客户端证书提供身份验证和授权机制,以保护网络及其资源的访问。
-
双向通信:MQTT 的发布-订阅模式为设备之间提供了无缝的双向通信方式。客户端既可以向主题发布消息,也可以订阅接收特定主题上的消息,从而实现了物联网生态系统中的高效数据交换,而无需直接将设备耦合在一起。这种模式也简化了新设备的集成,同时保证了系统易于扩展。
-
连续、有状态的会话:MQTT 提供了客户端与 Broker 之间保持有状态会话的能力,这使得系统即使在断开连接后也能记住订阅和未传递的消息。此外,客户端还可以在建立连接时指定一个保活间隔,这会促使 Broker 定期检查连接状态。如果连接中断,Broker 会储存未传递的消息(根据 QoS 级别确定),并在客户端重新连接时尝试传递它们。这个特性保证了通信的可靠性,降低了因间断性连接而导致数据丢失的风险。
-
大规模物联网设备支持:物联网系统往往涉及大量设备,需要一种能够处理大规模部署的协议。MQTT 的轻量级特性、低带宽消耗和对资源的高效利用使其成为大规模物联网应用的理想选择。通过采用发布-订阅模式,MQTT 实现了发送者和接收者的解耦,从而有效地减少了网络流量和资源使用。此外,协议对不同 QoS 等级的支持使得消息传递可以根据需求进行定制,确保在各种场景下获得最佳的性能表现。
-
语言支持:物联网系统包含使用各种编程语言开发的设备和应用。MQTT 具有广泛的语言支持,使其能够轻松与多个平台和技术进行集成,从而实现了物联网生态系统中的无缝通信和互操作性。
1.3.相关名词
客户端:使用MQTT的程序或设备。客户端总是通过网络连接到服务端。它可以
-
发布应用消息给其它相关的客户端。
-
订阅以请求接受相关的应用消息。
-
取消订阅以移除接受应用消息的请求。
-
从服务端断开连接。
服务端:一个程序或设备,作为发送消息的客户端和请求订阅的客户端之间的中介。它可以
-
接受来自客户端的网络连接。
-
接受客户端发布的应用消息。
-
处理客户端的订阅和取消订阅请求。
-
转发应用消息给符合条件的已订阅客户端。
订阅:订阅包含一个主题过滤器和一个最大的服务质量等级。订阅与单个会话关联。一个会话可以包含多个的订阅。会话的每个订阅都有一个不同的主题过滤器。 (与消息队列消费者订阅消息类似)
主题名:附加在应用消息上的一个标签,服务端已知且与订阅匹配。服务端发送应用消息的一个副本给每一个匹配的客户端订阅。 (与消息队列主题名类似)
主题过滤器:订阅中包含的一个表达式,用于表示相关的一个或多个主题。主题过滤器可以使用通配符。 (消费者过滤消息的条件)
会话:客户端和服务端之间的状态交互。一些会话持续时长与网络连接一样。(就是客户端到服务端的一次连接)
控制报文:通过网络连接发送的信息数据包。MQTT规范定义了十四种不同类型的控制报文,其中一个(PUBLISH报文)用于传输应用消息。 (可以理解为发布订阅的消息主体)
1.4.工作流程
-
客户端使用MQTT协议与 Broker 建立连接,可以选择使用 TLS/SSL 加密来实现安全通信。客户端提供认证信息,并指定会话类型(Clean Session 或 Persistent Session)。
-
客户端既可以向特定主题发布消息,也可以订阅主题以接收消息。当客户端发布消息时,它会将消息发送给 MQTT Broker;而当客户端订阅消息时,它会接收与订阅主题相关的消息。
-
MQTT Broker 接收发布的消息,并将这些消息转发给订阅了对应主题的客户端。它根据 QoS 等级确保消息可靠传递,并根据会话类型为断开连接的客户端存储消息。
第二章:MQTT控制报文格式
2.1.MQTT控制报文结构
2.2.固定报头
固定报头是MQTT协议开头,2个字节,分为三个部分:标志位、报文类型、剩余长度 。
2.2.1.控制报文的类型
表示为4位无符号值,位置在固定报头的第一个字节的前4位。
2.2.2.标志位
固定报头第1个字节的剩余的4位包含每个MQTT控制报文类型特定的标志。控制报文与标志位是相互对应的,必须设置为这些值, 如果收到非法的标志,接收者必须关闭网络连接。
2.2.3.剩余长度
从固定报头的第二个字节开始,表示当前报文剩余部分的字节数(剩余部分=可变报头+有效负载)。 剩余长度不包括用于编码剩余长度字段本身的字节数。 剩余长度的字节数是不固定的,至少一个字节,最多4个字节,所以固定报头中包含的一个字节就是剩余长度的第一个字节。剩余长度的每一个字节的最高位是一个标志位,用来表示下一个字节是否也属于剩余长度。
例:
01000000 最高位为0,则说明后面的字节数据不属于剩余长度了。
10100000 00000001 第一个字节最高位为1,则说明后面的字节数据属于剩余长度,第二个字节最高位为0,则说明后面没有属于剩余长度的字节了,那么此剩余长度则为这2个字节。
因为剩余长度的每个字节的最高位为标志位,所以其真实值并不是这些字节直接合并而成 。
如果第一个字节的最高位为0,则说明剩余长度只有一个字节,并且其值就是这个字节的值,如:01000000 那么剩余长度的真实值就是:64
如果剩余长度超过一个字节,那么就需要将每个字节的高字节去掉,然后组成一个新的数据,如: 10100000 00000001 去掉标志位即 0100000 0000001 重新合并,合并时后面的字节在高位即 10100000 则剩余长度的值为十进制的160;
2.3.可变报头
某些MQTT控制报文包含一个可变报头部分。它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同,一般是包含和报文类型相关的数据。例如客户端连接服务器报文,包含了协议名,协议级别、连接标志、保持连接等。
2.3.1.报文标识符
很多控制报文的可变报头部分包含一两字节的报文标识符字段。
不同报文类型的报文标识符有不同的作用:
SUBSCRIBE,UNSUBSCRIBE和PUBLISH(QoS大于0)控制报文必须包含一个非零的16位报文标识符。客户端每次发送一个新的这些类型的报文时都必须分配一个当前未使用的报文标识符。如果一个客户端要重发这个特殊的控制报文,在随后重发那个报文时,它必须使用相同的标识符。当客户端处理完这个报文对应的确认后,这个报文标识符就释放可重用。
PUBACK, PUBREC, PUBREL报文必须包含与最初发送的PUBLISH报文相同的报文标识符。
SUBACK和UNSUBACK必须包含在对应的SUBSCRIBE和UNSUBSCRIBE报文中使用的报文标识符。
2.4.有效载荷
某些MQTT控制报文类型的最后一个部分包含有效载荷,对于PUBLISH来说有效载荷就是消息主体。
第三章:MQTT控制报文
3.1.CONNECT – 连接服务端
客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文,在一个网络连接上,客户端只能发送一次CONNECT报文。服务端必须将客户端发送的第二个CONNECT报文当作协议违规处理并断开客户端的连接。此报文类型可以理解为对此次会话的一系列设置。
3.1.1.固定报头
3.1.2.可变报头
CONNECT报文的可变报头按下列次序包含四个字段:协议名(Protocol Name),协议级别(Protocol Level),连接标志(Connect Flags)和保持连接(Keep Alive)。
-
协议名:是表示协议名 MQTT 的UTF-8编码的字符串。MQTT规范的后续版本不会改变这个字符串的偏移和长度。如果协议名不正确服务端可以断开客户端的连接,也可以按照某些其它规范继续处理CONNECT报文。
- 协议级别:客户端用8位的无符号值表示协议的修订版本。对于3.1.1版协议,协议级别字段的值是4。如果发现不支持的协议级别,服务端必须给发送一个返回码为0x01(不支持的协议级别)的CONNACK报文响应CONNECT报文,然后断开客户端的连接。
- 连接标志:连接标志字节包含一些用于指定MQTT连接行为的参数。它还指出有效载荷中的字段是否存在。 服务端必须验证CONNECT控制报文的保留标志位(第0位)是否为0,如果不为0必须断开客户端连接。
清理会话 Clean Session: 连接标志字节的第1位。
客户端和服务端可以保存会话状态,以支持跨网络连接的可靠消息传输。这个标志位用于控制会话状态的生存时间。
如果清理会话标志被设置为0,服务端必须基于当前会话(使用客户端标识符识别)的状态恢复与客户端的通信。如果没有与这个客户端标识符关联的会话,服务端必须创建一个新的会话。当连接断开后,客户端 和服务端必须保存会话信息。当清理会话标志为0的会话连接断开之后,服务端必须将之后的QoS 1和QoS 2级别的消息保存为会话状态的一部分,如果这些消息匹配断开连接时客户端的任何订阅。服务端也可以保 存满足相同条件的QoS 0级别的消息。
如果清理会话(CleanSession)标志被设置为1,客户端和服务端必须丢弃之前的任何会话并开始一个新的会话。会话仅持续和网络连接同样长的时间。与这个会话关联的状态数据不能被任何之后的会话重用。
客户端的会话状态包括:①已经发送给服务端,但是还没有完成确认的QoS 1和QoS 2级别的消息。②已从服务端接收,但是还没有完成确认的QoS 2级别的消息。
服务端的会话状态包括:①会话是否存在,即使会话状态的其它部分都是空。②客户端的订阅信息。③已经发送给