MQTT的原理
一、MQTT 协议简介
MQTT(Message Queuing Telemetry Transport)是一种轻量级的物联网通信协议,由 IBM 推出,基于 TCP/IP 协议栈,运行于应用层。其核心设计目标是满足嵌入式设备、传感器与服务器之间的低带宽、低功耗通信需求,因此在物联网领域(如传感器数据采集、智能设备远程控制)中被广泛应用。
二、MQTT 的核心特性
-
开放与简洁
协议规范公开,实现简单,适合资源受限的硬件环境(如单片机、智能传感器)。 -
发布 / 订阅模式
- 采用 “一对多” 的消息传递机制:设备(发布者)将消息发送到指定 “主题(Topic)”,所有订阅该主题的设备(订阅者)可接收消息,无需直接建立连接,大幅降低应用耦合度。
- 例:智能家居中,智能门锁发布 “开门状态” 到
home/door
主题,手机 APP、安防系统等订阅者可实时获取信息。
-
基于 TCP 的可靠传输
主流 MQTT 依赖 TCP 实现有序、无损、双向的连接,确保消息传输的基础可靠性;另有基于 UDP 的变种MQTT-SN,适用于对实时性要求高但可容忍少量丢包的场景(如低功耗传感器网络)。 -
轻量低开销
- 协议头部固定长度仅 2 字节,额外开销极小,适合带宽有限的网络(如 GPRS、LoRa)。
- 最小化协议交互,减少数据传输量,降低设备能耗。
-
异常连接管理
支持连接断开通知机制,当设备意外离线时,服务器和相关订阅者可及时感知,便于进行重试或告警处理。 -
消息服务质量(QoS)分级
提供 3 种 QoS 级别,可根据业务需求选择可靠性与效率的平衡:- QoS 0(至多一次):
消息依赖 TCP 底层传输,无应答和重试机制,可能丢失或重复。
适用场景:环境传感器(如温度、湿度)数据,丢失单次读数不影响整体统计。 - QoS 1(至少一次):
接收方需通过PUBACK
消息确认,发送方未收到确认则重发(消息头标记DUP
位),确保消息至少送达一次(可能重复)。
适用场景:智能设备控制指令(如解锁共享单车),需确保指令被收到,重复执行影响较小。 - QoS 2(仅一次):
最高级别的可靠性,通过 “发送 - 确认 - 释放 - 完成” 四次交互确保消息唯一送达,无丢失或重复。
适用场景:计费系统、交易数据,需严格避免重复或丢失(如共享单车付费信息)。
- QoS 0(至多一次):
整体结构:
三、常用术语
以下是 MQTT 协议中关键术语的清晰解读,帮助理解其通信机制:
1. 网络连接(Network Connection)
MQTT 依赖 TCP 协议 作为底层传输基础设施,具备以下特性:
- 客户端通过它连接服务端,建立通信通道;
- 提供 有序、可靠、双向的字节流传输,保障消息稳定传递(如消息不丢失、不乱序)。
2. 应用消息(Application Message)
MQTT 协议传输的核心数据单元,包含两部分关联信息:
- 服务质量(QoS):定义消息的可靠传输级别(QoS 0/1/2);
- 主题(Topic):标记消息所属的 “类别”,订阅该主题的客户端可接收消息。
3. 客户端(Client)
使用 MQTT 协议的程序或设备(如智能传感器、手机 App、物联网网关),具备以下能力:
- 连接服务端,建立通信会话;
- 发布(Publish) 应用消息到指定主题,供其他客户端订阅;
- 订阅(Subscribe) 主题,接收相关消息;
- 取消订阅(Unsubscribe),停止接收某主题的消息;
- 主动断开与服务端的连接。
4. 服务端(Server)
作为客户端之间的 消息中介,承担核心转发职责:
- 接受客户端的网络连接,维护会话状态;
- 接收客户端发布的应用消息;
- 处理订阅 / 取消订阅请求,记录客户端的主题订阅关系;
- 将消息转发给 所有订阅匹配主题 的客户端。
5. 订阅(Subscription)
客户端与服务端约定的 “消息接收规则”,包含两个关键要素:
- 主题过滤器(Topic Filter):用通配符(如
+
、#
)匹配主题的表达式(如home/sensor/+
匹配home/sensor/temp
、home/sensor/hum
); - 最大服务质量(QoS):客户端接受消息时的最高 QoS 等级(服务端会自动降级,确保不超过该等级)。
- 订阅与 会话(Session) 关联,一个会话可包含多个订阅(如同时订阅
home/light
和home/door
)。
6. 主题名(Topic Name)
附加在应用消息上的 标签,用于标识消息类别(如 home/kitchen/temp
表示厨房温度数据)。
- 服务端根据主题名,匹配订阅的 “主题过滤器”,将消息转发给对应客户端。
7. 主题过滤器(Topic Filter)
订阅时使用的 主题匹配规则,支持通配符简化配置:
+
:单级通配符(如home/+/temp
匹配home/room1/temp
,但不匹配home/room1/sub/temp
);#
:多级通配符(如home/#
匹配home/
、home/room1/temp
等所有子主题,需放在主题结尾)。
8. 会话(Session)
客户端与服务端之间的 状态交互上下文,包含:
- 订阅关系(已订阅的主题过滤器);
- 未完成的消息(如 QoS 1/2 未确认的消息);
- 会话可与网络连接解耦:连接断开后,会话状态可保留(取决于服务端配置),重连后恢复通信。
9. 控制报文(MQTT Control Packet)
MQTT 协议定义的 十四种基础通信包,用于实现连接、发布、订阅等操作,例如:
CONNECT
:客户端发起连接请求;PUBLISH
:传输应用消息;SUBSCRIBE
:客户端订阅主题;PUBACK
:QoS 1 消息的确认包(确保至少送达一次)。
四、MQTT控制报文格式
一、报文整体结构
MQTT 控制报文由 报头(固定 + 可变) 和 负载 组成,规则如下:
组成部分 必选性 说明 固定报头(Fixed Header) 必须存在 标识报文类型、基础控制位,以及 “可变报头 + 负载” 的总字节数(剩余长度) 可变报头(Variable Header) 可选(部分报文有) 补充报文类型的额外信息(如报文标识符、主题名等) 负载(Payload) 可选(部分报文有) 实际传输的数据(如应用消息内容、订阅主题列表) 注:固定报头必须有,可变报头和有效负载可以没有。【固定报头】:第一个字节高4位是MQTT控制报文的类型 + 第一个字节低4位用于指定控制报文类型的标志位(只在 PUBLISH发布消息时用到) + 剩余长度1~4个字节(剩余长度字段最大4个字节)
剩余长度包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。剩余长度字段使用一个变长度编码方案,对小于 128 的值它使用单字节编码。更大的值按下面的方式处理。低 7 位有效位用于编码数据,最高有效位用于指示是否有更多的字节。因此每个字节可以编码 128 个数值和一个延 续位(continuation bit) 。 剩余长度字段最大4个字节。
二、固定报头(Fixed Header)
所有 MQTT 控制报文都包含固定报头,结构与编码规则如下:
1. 结构拆解
固定报头由 1 字节基础标识 + 1~4 字节剩余长度 组成:
(1)第一个字节(高 4 位 + 低 4 位)
- 高 4 位:
MQTT 控制报文类型
(共 14 种,如 PUBLISH=3、SUBSCRIBE=8 等);- 低 4 位:
控制位
(仅 PUBLISH 报文用,标识 QoS、DUP 等状态)。(2)剩余长度(Remaining Length)
- 作用:指示 “可变报头 + 负载” 的总字节数(不包含自身编码长度);
- 编码方式:采用 变长编码(低 7 位存数据,最高位存 “延续位”)
- 比如163被编码为(0xA,0x01):
- 16384拆分为(0x80,0x80,0x01):
- 最多用 4 字节,最大可表示
268435455
(约 2.68 亿字节)。2. 示例(PUBLISH 报文)
假设 PUBLISH 报文的 “可变报头 + 负载” 共
5
字节,固定报头构造:
- 高 4 位:
0011
(PUBLISH 类型);- 低 4 位:
0010
(QoS=1 的控制位);- 剩余长度:
05
(单字节编码,因5 < 128
);- 最终固定报头:
0x32 0x05
(十六进制表示)。
三、可变报头(Variable Header)
(一)基础定义
可变报头是 MQTT 控制报文的中间组成部分,位于固定报头和负载之间 ,其内容会根据报文类型动态变化 ,核心作用是为特定类型的报文补充关键元信息,像报文标识符(Packet Identifier)就是可变报头里高频出现的重要字段。
(二)报文标识符(Packet Identifier)
1. 涉及的报文类型
有 9 种控制报文会包含报文标识符(2 字节长度),分别是:
PUBLISH(QoS>0 时)、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK
。这些报文依靠标识符实现消息关联、重传确认等逻辑,是 MQTT 可靠通信的关键支撑。2. 注意事项与规则(附示例说明)
独立分配,支持并发
客户端和服务端各自独立生成报文标识符。比如客户端用0x0001
发PUBLISH
报文,服务端同时能用0x0001
发SUBSCRIBE
响应,互不干扰,让双方可并行处理多组消息交互,提升通信效率。
举个实际场景:智能家居系统里,手机 App(客户端)给智能灯(服务端)发PUBLISH
调光指令(QoS=1
,标识符0x0002
),同时智能门锁(服务端)给手机 App 发PUBLISH
开锁状态(QoS=1
,标识符0x0002
),两者能正常交互,不会因标识符重复出问题。非零要求(特定报文)
SUBSCRIBE
、UNSUBSCRIBE
以及QoS>0
的PUBLISH
报文,必须带非零的 16 位报文标识符。若填0x0000
,服务端会判定报文非法并丢弃。
比如开发环境传感器数据上传程序,若PUBLISH
报文(QoS=1
)标识符设为0x0000
,服务端接收后会直接拒绝,导致数据上传失败,得排查代码里标识符赋值逻辑。新报文用新标识符,重传复用
客户端发新的上述类型报文时,得选当前未用过的标识符;若报文因网络问题需重传(像QoS=1
的PUBLISH
没收到PUBACK
),重传报文得用原标识符,等收到服务端确认,该标识符才释放,可用于新报文。
举个例子:物联网温湿度传感器(客户端)定时发PUBLISH
报文(QoS=1
,标识符0x0003
)传数据,若首次发送后网络延迟,没收到PUBACK
,传感器重传时还得用0x0003
,收到服务端PUBACK
后,0x0003
才可用作下次新数据上传的标识符。QoS=0 的 PUBLISH 无标识符
QoS=0
的PUBLISH
报文,因无需确认和重传,不会带报文标识符,能减少报文长度,提升传输效率。
比如智能电表按固定周期(5 分钟)用QoS=0
发用电数据,报文结构里就没有标识符字段,简单直接传数据,适合这类对可靠性要求不高、高频次的数据上报场景。确认报文复用标识符
PUBACK
、PUBREC
等确认类报文,得用对应PUBLISH
报文的标识符;SUBACK
、UNSUBACK
得用对应SUBSCRIBE
、UNSUBSCRIBE
的标识符,让服务端和客户端精准关联请求与响应。
举个场景:手机 App(客户端)发SUBSCRIBE
报文(标识符0x0004
,订阅客厅温湿度主题),服务端处理后,回SUBACK
报文时,标识符也得是0x0004
,App 收到后,就知道这是对之前订阅请求的响应,能正确更新本地订阅状态。作用:动态决定字段包含
可变报头里是否带报文标识符等字段,由报文类型和控制位(像QoS
等级)决定。比如QoS=0
的PUBLISH
,因规则 4 ,可变报头就不含标识符;QoS=1
的PUBLISH
,可变报头就得有标识符,实现可靠传输逻辑。
四、有效在载荷
(一)基础定义
有效载荷是报文里实际承载业务数据的部分,位于可变报头之后(若有可变报头),部分 MQTT 控制报文会包含它,用于传输像应用消息内容、订阅主题列表这类关键信息。
(二)涉及的报文类型与示例
可能包含有效载荷的控制报文有:
CONNECT
、PUBLISH
、SUBSCRIBE
、SUBACK
、UNSUBSCRIBE
,以下分述:
- CONNECT
有效载荷包含客户端标识符、遗嘱消息(若配置)、用户名、密码等信息。比如 MQTT 客户端连服务器时,CONNECT
报文的有效载荷里,客户端标识符填device_001
,用户名user01
,密码123456
,用于服务端认证和标识客户端。
实际开发中,智能家居网关作为客户端连云平台,CONNECT
报文有效载荷带这些信息,云平台验证通过后,才建立连接,让网关能上报设备状态、接收控制指令。- PUBLISH
有效载荷就是应用消息本身 。比如环境监测设备发PUBLISH
报文传温湿度数据,有效载荷可能是 JSON 格式字符串{"temp":25.5,"humidity":60}
,订阅该主题的客户端(像手机 App、监控平台)收到后,解析展示数据。
比如智能农业场景里,田间传感器用PUBLISH
发土壤湿度数据,有效载荷存具体数值,农场管理系统订阅后,依据这些数据自动控制灌溉设备。- SUBSCRIBE
有效载荷包含要订阅的主题过滤器列表 及对应QoS
等级。比如客户端发SUBSCRIBE
报文订阅home/sensor/temp
(QoS=1
)和home/sensor/hum
(QoS=0
)两个主题,有效载荷就会按 MQTT 格式,依次存这两个主题过滤器和对应的QoS
值,服务端收到后,会记录客户端的订阅关系,后续有对应主题消息,就推送给客户端。
开发智能家居 App 时,用户想关注客厅和卧室的温度,App 发SUBSCRIBE
报文,有效载荷带home/livingroom/temp
(QoS=1
)、home/bedroom/temp
(QoS=1
),服务端处理后,这两个房间的温度数据更新,就会推送给 App 。- SUBACK
有效载荷包含服务端对订阅请求的确认信息 ,像实际授予的QoS
等级。比如客户端请求订阅QoS=1
,但服务端因资源或策略限制,实际授予QoS=0
,SUBACK
的有效载荷就会带回这个最终QoS
,客户端收到后,调整本地消息接收逻辑,确保和服务端一致。
比如 IoT 设备管理平台限制某些主题的QoS
最高为0
,设备端发SUBSCRIBE
要QoS=1
,SUBACK
有效载荷带回QoS=0
,设备端就得按QoS=0
处理后续消息接收,避免因双方QoS
不一致,导致消息处理异常。- UNSUBSCRIBE
有效载荷包含要取消订阅的主题过滤器列表 。比如客户端之前订阅了home/light
和home/door
主题,现在要取消订阅home/light
,UNSUBSCRIBE
报文的有效载荷就存home/light
这个主题过滤器,服务端收到后,移除该客户端对这个主题的订阅关系,后续对应主题消息就不再推送给客户端。
比如手机 App 里,用户不想接收客厅灯光状态通知了,App 发UNSUBSCRIBE
报文,有效载荷带home/livingroom/light
主题,服务端处理后,App 就收不到该主题的消息了,能减少不必要的流量消耗。