一、什么是MQTT
物联网 (IoT) 和机器对机器 (M2M) 通信对我们与技术交互的方式产生了持久影响。到 2022 年底,全球连接的物联网设备数量增长了 18%,达到 144 亿,到 2025 年估计连接的物联网设备将达到约 270 亿。随着这种增长,能够处理设备和处理系统(通常位于云端)之间实时、可靠和高效通信的消息传递协议至关重,因此,MQTT协议应运而生
Message Queuing Telemetry Transport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与 HTTP 一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。
• MQTT(MQ Telemetry Transport)是一种轻量级的开放式消息传递协议,它为资源受限的网络客户端提供了一种在低带宽环境中分发遥测信息的简单方法。该协议采用发布/订阅(PUSH/SUBSCRIBE)的通信模式,用于机器对机器 (M2M) 通信。
• MQTT 是为适应带宽和 CPU 限制而创建的低开销协议,旨在在嵌入式环境中运行,在该环境中它可以提供可靠、有效的通信路径。MQTT 适用于连接代码占用空间小的设备,对于由于偶尔的带宽限制或不可靠连接而经历不同级别延迟的无线网络来说,是一个不错的选择。该协议在汽车、能源和电信等物联网行业都有应用
• 尽管 MQTT 最初是用于与石油和天然气行业的监控和数据采集 (SCADA) 系统通信的专有协议,但它已在智能设备领域变得流行,如今已成为连接物联网的领先开源协议
• 最初,“MQTT”中的“MQ”来源于IBM的MQ(当时称为MQSeries)产品线,代表“Message Queue”。然而,尽管它的名称如此,该协议并不使用消息队列;相反,它提供发布和订阅消息传递:设备发布关于特定主题的消息,所有订阅该主题的设备都会收到该消息。它的主要应用包括发送消息以控制输出,以及从传感器节点读取和发布数据
原理:
(1)MQTT协议身份和消息格式
有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。
MQTT传输的消息分为:主题(Topic)和负载(payload)两部分
- Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload)
- payload,消息的内容
(2) 网络传输与应用消息
MQTT会构建底层网络传输:它将建立客户端到服务器的连接,提供两者之间的一个有序的、无损的、基于字节流的双向传输。
应用数据通过MQTT网络发送时,MQTT会把与之相关的服务质量(QoS)和主题名(Topic)相关连
(3)MQTT客户端作用
- 发布其他客户端可能会订阅的信息
- 订阅其它客户端发布的消息
- 退订或删除应用程序的消息
- 断开与服务器连接
(4)MQTT服务端作用
可以是一个应用程序或一台设备
- 接受来自客户的网络连接
- 接受客户发布的应用信息
- 处理来自客户端的订阅和退订请求
- 向订阅的客户转发应用程序消息
(5) MQTT协议中的订阅、主题、会话
订阅(Subscription):
订阅包含主题筛选器(Topic Filter)和最大服务质量(QoS)。订阅会与一个会话(Session)关联。一个会话可以包含多个订阅。每一个会话中的每个订阅都有一个不同的主题筛选器会话(Session):
每个客户端与服务器建立连接后就是一个会话
主题名(Topic Name):
就是连接到一个应用程序消息的一个标签。该标签与服务器的订阅的相匹配,服务器会将消息发送给订阅所匹配标签的每个客户端。
主题筛选器(Topic Filter):
表示订阅所匹配到的多个主题
负载(Payload):
其实就是内容。消息订阅者所具体接收的内容
二、MQTT的工作原理
Mqtt的工作原理可以概括为:MQTT 通过其两个主要组件来实现发布/订阅模型:客户端和代理
• 客户端(client)是发布或订阅消息的设备或应用程序,分别使它们成为所谓的发布者或订阅者。客户端可以向主题发布消息,主题是消息发送到的逻辑通道。订阅者可以是一个或多个客户端,接收发布到主题的消息。客户端也可以同时充当发布者和订阅者
• 另一方面,代理端(broker)是在客户端之间路由消息的中间服务器。代理通过跟踪订阅和向订阅的客户端发布消息来管理客户端之间的消息分发。MQTT 客户端可以用多种编程语言实现,可以在各种硬件平台上运行,从低功耗微控制器到功能强大的服务器。代理可以部署在云端或本地,并且可以水平扩展以支持每秒数百万的设备和消息。阿里云、华为云、AWS 或 Azure 等超大规模应用程序都围绕其服务提供 MQTT 包装器,对 MQTT 协议提供不同级别的支持
消息通过使用 MQTT 的代理与其他设备或软件共享。每条消息都有一个主题(Topic),Broker 可以根据该主题进一步处理消息。此外,每条消息都包含一个消息内容,即所谓的有效负载(payload)。MQTT 负载不绑定特定结构,可以自由设计。然而,为消息内容指定一个特定的结构是有帮助的,这样它就可以被其他设备或软件读取。潜在的消息结构可以是 JSON、XML 或 OPC UA。只要所有设备和软件都使用相同的结构进行通信,定义的结构就可以实现顺畅的内部通信
当订阅客户端失去与代理的连接时,代理可以 根据用例和实现 - 保留任何旨在发送给订阅者的消息,然后在订阅者重新连接时立即传递它们。这确保订阅者不会错过任何消息并以正确的顺序接收它们,在国内简称遗嘱机制
二、MQTT协议的特点
轻量、简单、开放,是低开销、低带宽占用的即时通讯协议。使用场景有:机器与机器(M2M)、物联网(IoT)。MQTT协议当前版本为,2014年发布的MQTT v3.1.1。除标准版外,还有一个简化版MQTT-SN,该协议主要针对嵌入式设备,这些设备一般工作于TCP/IP网络,如ZigBee
使用的发布/订阅消息模式,它提供了一对多消息分发,以实现与应用程序的解耦。
对负载内容屏蔽的消息传输机制。
对传输消息有三种服务质量(QoS):
1.QoS 0:最多一次,这一级别会发生消息丢失或重复,消息发布依赖于底层TCP/IP网络。即:<=1
2.QoS 1:最少一次(承诺消息将至少传送一次给订阅者),这一级别会确保消息到达,但消息可能会重复。即:>=1
3.QoS 2:只有一次(承诺消息仅传送到目的地一次),确保消息只有一次到达。即:=1。在一些要求比较严格的计费系统中,可以使用此级别
(注意:带有唯一消息 ID 的消息会存储两次,首先来自发送者,然后是接收者。QoS 级别 2 在网络中具有最高的开销,因为在发送方和接收方之间需要两个流)
数据传输和协议交换的最小化(协议头部只有2字节),以减少网络流量
通知机制,异常中断时通知传输双方
三、MQTT协议数据包结构
MQTT 是一种基于二进制的协议,控制元素是二进制字节而不是文本字符串
命令和命令确认格式由 MQTT 使用,这意味着每个命令都有一个伴随的确认。连接命令有连接确认,订阅命令有订阅确认,发布命令有发布确认,如上图所示。这种机制类似于 TCP 协议的握手机制
MQTT 消息格式由3字段组成
• 固定包头(Fixed Header)所有 MQTT 数据包都必须存在,固定占用2个字节
• 可变包头(Variable Header)并不总是存在,有时候不存在这个部分
• 包体(payload)正在发送的数据存储在有包体中,然而包体部分也并不总是存在,一些命令,例如断开消息,就不使用包体字段
固定包头报文解析
固定包头包含 2 个字节,
第一个字节的前4位(Bit7Bit4)表示消息类型,后4位(Bit3Bit0)用于表示传输协议和Qos等级,
第二字节用于存储数据包长度,这个长度=可变包头长度+包体长度
MQTT Control Packet Types:
Name | Value | Direction of Flow | Description |
Reserved | 0 | Forbidden | Reserved |
CONNECT | 1 | Client To Server | Connection Request |
CONNACK | 2 | Server To Client | Connection Acknowledgement |
PUBLISH | 3 | Client To Server Or Server To Client | Publish Message |
PUBACK | 4 | Client To Server Or Server To Client | Publish Acknowledgement |
PUBREC | 5 | Client To Server Or Server To Client | Publish Received |
PUBREL | 6 | Client To Server Or Server To Client | Publish Release |
PUBCOMP | 7 | Client To Server Or Server To Client | Publish Complete |
SUBSCRIBE | 8 | Client To Server | Subscribe Request |
SUBACK | 9 | Server To Client | Subscribe Acknowledgement |
UNSUBSCRIBE | 10 | Client To Server | Unsubscribe request |
UNSUBACK | 11 | Server To Client | Unsubscribe Acknowledgement |
PINGREQ | 12 | Client To Server | Ping Request |
PINGRESP | 13 | Server To Client | Ping Response |
DISCONNECT | 14 | Client To Server Or Server To Client | Disconnect Notification |
AUTH | 15 | Client To Server Or Server To Client | Authentication Exchange |
Flag Bit:
MQTT Control Packet | Fixed Header Flags | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
CONNECT | Reserved | 0 | 0 | 0 | 0 |
CONNACK | Reserved | 0 | 0 | 0 | 0 |
PUBLISH | MQTT v5.0 | DUP | QoS | RETAIN | |
PUBACK | Reserved | 0 | 0 | 0 | 0 |
PUBREC | Reserved | 0 | 0 | 0 | 0 |
PUBREL | Reserved | 0 | 0 | 0 | 0 |
PUBCOMP | Reserved | 0 | 0 | 0 | 0 |
SUBSCRIBE | Reserved | 0 | 0 | 0 | 0 |
SUBACK | Reserved | 0 | 0 | 0 | 0 |
UNSUBSCRIBE | Reserved | 0 | 0 | 0 | 0 |
UNSUBACK | Reserved | 0 | 0 | 0 | 0 |
PINGREQ | Reserved | 0 | 0 | 0 | 0 |
PINGRESP | Reserved | 0 | 0 | 0 | 0 |
DISCONNECT | Reserved | 0 | 0 | 0 | 0 |
AUTH | Reserved | 0 | 0 | 0 | 0 |
可变包头(Variable Header)解析
可变标头组件作为可选字段包含在某些 MQTT 控制数据包类型中。在固定报头和有效载荷之间是这个字段。可变标头的内容由数据包类型决定。在可变报头中可以找到许多数据包类型中常见的数据包标识符字段。数据包标识符字段是一个 2 字节整数,包含在许多 MQTT 控制数据包类型的可变标头组件中。
数据包标识符字段在下面的列表中给出:
• PUBLISH
• PUBACK
• PUBREC
• PUBREL
• PUBCOMP
• SUBSCRIBE
• SUBACK
• UNSUBSCRIBE
• UNSUBACK
数据包标识符字段的特征:
-
1. 如果 QoS(服务质量)的值设置为零,则 PUBLISH 数据包不应包含数据包标识符字段。这意味着如果 QoS 值大于零,则数据包标识符字段将仅出现在 PUBLISH 数据包中。
-
2. 客户端在发送新的 SUBSCRIBE、UNSUBSCRIBE 或 PUBLISH MQTT 控制数据包时应分配一个当前未使用的非零数据包标识符。
-
3. 服务器在发送新的 PUBLISH MQTT 控制数据包时应分配一个当前未使用的非零数据包标识符。
-
4. PUBACK、PUBREC、PUBUREL、PUBREC是PUBLISH命令确认包,包标识符与PUBLISH包相同
-
5. SUBACK和UNSUBACK分别是SUBSCRIBE和UNSUBSCRIBE确认包。SUBACK 和 UNSUBACK 数据包与 SUBSCRIBE 和 UNSUBSCRIBE 数据包共享相同的数据包标识符
-
6. 处理完相应的确认包后,包标识符可以重复使用。下面是一个定义:
A。如果 QoS 设置为 1,则 PUBLISH 的确认包将是 PUBACK。如果处理了 PUBACK,则可以重用 PUBACK 数据包标识符。
B.如果 QoS 值为 2,则 PUBLISH 确认包将是 PUBCOMP 或 PUBREC。
包体(payload)
包体是消息格式中的最后一个 MQTT 控制数据包。该字段保存将要发送的数据。
MQTT Control Packet | Payload |
CONNECT | Required |
CONNACK | None |
PUBLISH | Optional |
PUBACK | None |
PUBREC | None |
PUBREL | None |
PUBCOMP | None |
SUBSCRIBE | Required |
SUBACK | Required |
UNSUBSCRIBE | Required |
UNSUBACK | Required |
PINGREQ | None |
PINGRESP | None |
DISCONNECT | None |
AUTH | None |
四、MQTT5.0新特性
MQTT 协议是当今世界上使用最广泛、最受欢迎的 TCP/IP 物联网协议。毫不奇怪,该协议的广泛采用导致对进一步开发 MQTT 规范的高需求。MQTT 5 试图满足这种需求。在制造系统和物流领域,以及智能家居应用,以及企业物联网应用和移动应用,都是流行的 MQTT v5 用例
MQTT 5.0 版中的新功能旨在实现以下目标:
• 大规模系统性能:现在,数千(如果不是数百万)设备之间的通信更加简化。没有协议约束,但需要 MQTT 5 适当的架构来组织这么多设备。
• 报错:MQTTv5.0协议中的return code改名为reason code,可以指示更大范围的故障。
• 实现了常见的交互:当前版本已经标准化了许多设备相互交互的方式。该系统现在包括定义参与设备的能力以及它们如何响应查询的能力。
• 包括可扩展性机制:现在可以指定自定义属性,以及内容类型或有效负载格式。
• 更好的支持:特别适用于希望使用此最新协议版本来提高工作效率的小型用户。
MQTT5和MQTT3有什么不同
MQTT v5.0 是 MQTT 3.1 的继任者。最重要的是,MQTTv5.0 不支持向后兼容性(如 v3.1.1 )。由于引入了如此多的新项目,因此必须重新审视当前的实施。以下是一些V5和V3不一样的地方:
• Session Expiry Interval 属性可用于实现会话过期。例如,订阅时间可能包含在主题中,以及消息将保留的时间量
• 对MQTT客户端和服务器的限制可以内置最大数据包大小(广播的字节数)和最大接收等限制(客户端或服务器,同时发送的消息数) .
• Will Delay Interval 是一个允许您在计时器上发送消息的属性。
• 服务器重定向或服务器引用是有助于在代理或服务器之间传输数据包的属性。
• Message Expiry Interval 是消息在过期前存储的时间量。
• 有效载荷格式指示符和内容类型——可以使用的有效载荷标志的种类由此属性定义:字节(二进制)、UTF-8 或 MIME 类型。
• 主题别名 – 例如,别名 1 分配给主题。那么这个功能可以通过减少您需要的数据包数量来帮助您。
• 响应主题——当使用响应主题时,该协议的工作方式类似于具有响应-请求方案的 HTTP 协议。
• 非本地发布- 用户可以选择是否要接收来自客户端的消息。
• Retained Message Control – 消息的顺序由该选项控制。
• 订阅标识符,用于标识服务器上的订阅。
• 可以共享的订阅允许具有额外符号和过滤选项的更灵活的订阅。
• 所有 ACK 消息上的原因代码 - 过程中的任何时候都可能发生错误。在 MQTTv3.1.1 中,很少有来自服务器的关于在建立通信、发送消息或订阅主题等各个阶段出了什么问题的信息。
• 服务器断开连接 - 与 3.1 不同,MQTT 5.0 允许从客户端和服务器端发送有关断开连接的数据包。
• 用户属性——键可用于存储各种属性的值。
• 增强型身份验证——查询/响应式身份验证方法的机制,它在客户端和服务器之间执行双向身份验证。
对于大多数物联网用例,MQTT 5 规范已成为合乎逻辑的选择。MQTT 5 的新特性成功解决了版本 3 的局限性,同时也为未来的发展开辟了道路。未来几年,协议的采用预计将在所有行业激增,包括工业、汽车、关键基础设施、物流、智慧城市等。MQTT 即将成为连接到物联网的所有事物的行业标准。