MQTT协议
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是一种基于发布 / 订阅(Publish/Subscribe)模式的轻量级物联网通信协议,由 IBM 在 1999 年设计,核心目标是在低带宽、不稳定网络环境下,实现设备间高效、可靠的小数据量通信,广泛应用于物联网(IoT)、工业物联网(IIoT)、智能家居、远程监控等场景。
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是一种基于发布/订阅(Publish/Subscribe)模式的轻量级物联网通信协议,由IBM在1999年设计,核心目标是在低带宽、不稳定网络环境下,实现设备间高效、可靠的小数据量通信,广泛应用于物联网(IoT)、工业物联网(IIoT)、智能家居、远程监控等场景。
MQTT协议具有如下特性
- 轻量级:协议头部开销极小(固定头部仅2字节),客户端代码体积小、资源消耗低,适配单片机、传感器等算力/存储有限的设备。
- 发布/订阅模式:不同于传统的点对点通信,MQTT通过“主题(Topic)”实现消息解耦:
- 发布者(Publisher):仅负责向指定主题发送消息,无需知道订阅者的存在;
- 订阅者(Subscriber):仅关注感兴趣的主题,接收该主题下的所有消息;
- 代理(Broker):核心中间件,负责接收发布者的消息、匹配订阅关系,并将消息推送给对应订阅者。
- QoS(Quality of Service)消息质量等级:支持三种等级,适配不同可靠性需求:
- QoS 0:最多一次交付,消息发送后无需确认,可能丢失(适用于非关键数据,如温湿度实时采集);
- QoS 1:至少一次交付,消息会被确认,确保送达但可能重复(适用于重要数据,如设备指令);
- QoS 2:恰好一次交付,通过两次握手+消息唯一标识确保消息仅送达一次(适用于核心数据,如金融交易、设备状态变更)。
- 持久化与会话保持:
- 订阅持久化:订阅者可设置“持久化订阅”,即使离线,Broker也会缓存对应主题的消息,待其重连后推送;
- 遗嘱消息(Last Will and Testament,LWT):客户端连接时可预设“遗嘱”,若异常断开(如网络中断、设备故障),Broker会自动将遗嘱消息发送到指定主题,用于设备异常告警。
- 低带宽适配:采用二进制编码格式,相比HTTP等文本协议,数据传输效率更高,适合窄带网络(如2G/3G、LoRa)。
核心架构
MQTT的通信架构包含三类角色:
- 客户端(Client):可以是发布者、订阅者,或同时兼具两种身份(如智能灯既订阅“开关指令”主题,也发布“运行状态”主题);
- 代理(Broker):核心枢纽,负责管理客户端连接、主题匹配、消息转发,主流的MQTT Broker有EMQ X、Mosquitto、AWS IoT Core等;
- 服务器(Server):通常Broker部署在服务器端,客户端通过TCP/IP(或WebSocket)与Broker建立连接。
典型通信流程:
- 客户端与Broker建立TCP连接,完成身份认证(支持用户名密码、TLS/SSL加密);
- 订阅者向Broker发送“订阅请求”,指定感兴趣的主题(如“home/bedroom/temperature”);
- 发布者向Broker发送“发布请求”,指定主题并携带消息(如“25℃”);
- Broker根据订阅关系,将消息推送给所有订阅该主题的客户端;
- 客户端完成通信后,可主动断开连接,或保持长连接等待后续消息。
一、MQTT Broker、发布者、订阅者的通用部署逻辑
MQTT各角色的部署核心是Broker作为中心枢纽,发布者/订阅者作为终端客户端,部署形态随场景(家用/工业/商用)灵活调整,核心原则如下:
| 角色 | 部署位置/方式 | 核心要求 |
|---|---|---|
| MQTT Broker | 1. 云部署(主流):部署在公有云(阿里云IoT、腾讯云IoT、AWS IoT Core)或私有云服务器,通过公网提供服务; 2. 本地部署:家用场景常内置在智能网关、路由器或本地服务器(如树莓派),断网时仍可本地通信 |
稳定的网络/算力、支持高并发连接、消息持久化、权限管理(如ACL)、TLS加密 |
| 发布者/订阅者 | 部署在终端设备(硬件/软件),只要能运行MQTT客户端库、通过TCP/IP/WebSocket联网即可 | 轻量化(适配设备算力)、支持MQTT协议核心指令(连接、发布、订阅、断开) |
注:发布者和订阅者并非“固定角色”——同一设备可同时是发布者+订阅者(如智能灯既发布状态,也订阅控制指令)。
下面以手机APP + 智能网关 + 智能灯的场景为例,说明三者的角色
二、手机APP监控家用智能灯的场景
家用智能灯的MQTT通信通常分两种架构(取决于网关是否内置Broker),以下是最常见的“云Broker+网关桥接”架构(断网时可降级为本地Broker):
核心角色定义
| 设备 | 核心角色 | 具体职责 |
|---|---|---|
| 智能灯 | 主要为发布者,次要为订阅者 | 1. 发布者:实时向指定Topic发布自身状态(如“home/livingroom/light/status”,消息内容:“开启/亮度80%/色温4000K”); 2. 订阅者:订阅控制指令Topic(如“home/livingroom/light/control”),接收手机APP的开关/调光指令 |
| 智能网关 | 网络桥接器 + 可选本地Broker | 1. 桥接:智能灯多为低功耗无线设备(ZigBee/蓝牙),无法直接连公网,网关将ZigBee/蓝牙协议转换为TCP/IP,代理智能灯与云端Broker通信; 2. 本地Broker(可选):若网关内置Mosquitto等轻量Broker,断网时可在本地完成智能灯与手机(局域网)的MQTT通信 |
| 手机APP | 主要为订阅者,次要为发布者 | 1. 订阅者:向Broker订阅智能灯状态Topic,实时接收灯的照明情况; 2. 发布者:向控制指令Topic发布操作指令(如“关闭/调亮至100%”); 3. 额外:APP需内置MQTT客户端SDK,完成与Broker的连接、认证、订阅/发布操作 |
| 云端MQTT Broker | 核心消息枢纽 | 1. 接收智能灯(经网关)发布的状态消息; 2. 匹配订阅关系:将状态消息推送给订阅该Topic的手机APP; 3. 接收手机APP发布的控制指令,推送给智能灯(经网关); 4. 可选:持久化消息(如智能灯离线时缓存控制指令,重连后推送) |
完整通信流程(云Broker架构)
- 智能网关接入家庭网络,与云端Broker建立长连接,并完成身份认证(设备证书/用户名密码);
- 智能灯通过ZigBee/蓝牙连接网关,网关为智能灯分配唯一标识,代理其完成MQTT客户端初始化;
- 手机APP打开后,通过移动网络/家庭WiFi连接云端Broker,订阅“home/livingroom/light/status”主题;
- 智能灯实时采集自身状态(如亮度、开关状态),通过网关将消息发布到上述主题;
- 云端Broker识别到该主题有订阅者(手机APP),将状态消息推送给手机APP,APP解析后展示照明情况;
- 若用户在APP操作(如关灯),APP向“home/livingroom/light/control”发布“关闭”指令;
- Broker将指令推送给网关,网关转换为ZigBee/蓝牙指令下发给智能灯,智能灯执行操作后,再次发布更新后的状态到状态主题,APP同步显示。
补充:本地Broker架构(断网场景)
若网关内置MQTT Broker(如小米网关、涂鸦智能网关),断网时:
- 手机APP通过家庭WiFi连接网关内置的本地Broker;
- 智能灯仍通过网关与本地Broker通信;
- 所有消息转发在本地完成,无需公网,保证断网时监控/控制功能可用。
三、关键补充
- 权限控制:Broker会为每个设备(智能灯、手机APP、网关)分配独立的身份凭证,仅允许智能灯发布状态Topic、订阅控制Topic,避免非法设备篡改指令;
- 低功耗优化:智能灯作为MQTT客户端,会采用“长连接+心跳包”机制,既保证实时通信,又降低功耗(心跳间隔可配置,如30秒);
- Topic设计:家用场景的Topic通常按“区域/设备类型/设备ID/消息类型”分层,如“home/bedroom/light/123/status”(123为灯的唯一ID),便于Broker精准路由。
Qos
MQTT的QoS(Quality of Service,服务质量等级)是协议核心的可靠性保障机制,定义了消息从发布者经Broker(代理)到订阅者的交付规则,共分为0、1、2三个等级——等级越高,消息交付的可靠性越强,但通信开销、延迟和协议复杂度也越高,可根据业务场景灵活选择。
核心原则
QoS的保障范围是“单段链路”(发布者↔Broker、Broker↔订阅者),最终实际生效的QoS为两段链路中较低的等级(例如发布者以QoS 2发布,订阅者以QoS 1订阅,最终按QoS 1交付);且QoS仅保障“消息送达”,不保障“消息顺序”(需业务层或Broker配置实现顺序性)。
各QoS等级详细解析
1. QoS 0:最多一次(At Most Once)
- 核心定义:消息仅发送一次,发送方(发布者/Broker)无需接收方确认,消息可能送达、也可能丢失(无重传、无确认机制)。
- 通信流程(极简):
- 发布者 → Broker:直接发送消息,不等待Broker的确认(PUBACK);
- Broker → 订阅者:直接转发消息,不等待订阅者的确认。
- 关键特点:
- 开销最小(仅一次消息传输)、延迟最低,仅依赖TCP的基础可靠性(TCP丢包则消息直接丢失);
- 无消息重传、无重复风险,但存在丢失风险。
- 适用场景:非关键、可容忍丢失的实时数据,例如:
- 智能家居:智能灯的实时亮度/色温采集、温湿度传感器的秒级数据上报;
- 工业场景:车间设备的实时转速/温度(丢一条不影响整体监控)。
2. QoS 1:至少一次(At Least Once)
- 核心定义:确保消息至少送达一次,发送方会重传消息直到收到接收方的确认,可能出现消息重复(但绝对不会丢失)。
- 通信流程(带确认+重传):
阶段1:发布者 → Broker
- 发布者发送消息(携带唯一16位Message ID,用于标识消息);
- Broker收到消息后,返回PUBACK(发布确认);
- 若发布者超时未收到PUBACK,会重复发送该消息(直到收到确认)。
阶段2:Broker → 订阅者
- Broker向订阅者转发消息(复用Message ID);
- 订阅者收到后返回PUBACK;
- 若Broker超时未收到PUBACK,会重发消息。
- 关键特点:
- 可靠性高于QoS 0,有少量额外开销(确认包+可能的重传);
- 存在消息重复风险(需业务层通过Message ID或唯一标识去重)。
- 适用场景:重要、不允许丢失但可容忍重复的数据,例如:
- 智能家居:智能门锁的开锁/关锁指令、智能灯的开关指令(重复收到仅执行一次);
- 告警场景:设备离线告警、低电量提醒(必须送达,重复告警无影响)。
3. QoS 2:恰好一次(Exactly Once)
- 核心定义:确保消息仅送达一次,无丢失、无重复,是MQTT最高级别的可靠性保障(开销最大)。
- 通信流程(两次握手+唯一标识,分“发布者→Broker”和“Broker→订阅者”两段,流程一致):
以“发布者→Broker”为例:- 发布者发送消息(带Message ID),Broker收到后返回PUBREC(发布收到);
- 发布者收到PUBREC后,发送PUBREL(发布释放),确认“已收到Broker的接收确认”;
- Broker收到PUBREL后,保存消息并返回PUBCOMP(发布完成),发布者收到后终止重传;
- 若任意步骤超时,发送方会重传对应指令(而非整条消息),确保流程闭环。
(Broker→订阅者的流程完全复用上述步骤,仅角色互换)
- 关键特点:
- 完全可靠(无丢失、无重复),但通信步骤多、延迟高、开销最大;
- 依赖Message ID和四段式握手,Broker需临时持久化消息直到流程完成。
- 适用场景:核心、不可重复、不可丢失的数据,例如:
- 金融场景:支付指令、交易记录上报;
- 物联网计费:智能电表/水表的用电量/用水量上报(重复会导致计费错误);
- 设备控制:工业机器人的动作指令(重复执行会导致设备故障)。
QoS关键补充说明
- Message ID的作用:QoS 1/2的消息均携带16位Message ID(范围0~65535),用于标识消息、实现重传和去重,同一客户端的Message ID会循环使用。
- 持久化机制:QoS 1/2的消息会被Broker持久化存储,直到确认送达订阅者,避免Broker重启后消息丢失;QoS 0的消息仅在内存中暂存,重启即丢失。
- 开销对比(从低到高):QoS 0 < QoS 1 < QoS 2,实际选型需平衡“可靠性需求”和“设备/网络开销”(例如低功耗传感器优先选QoS 0,核心指令选QoS 1/2)。
代码示例
一、整体方案说明
本次示例基于家用网关内置MQTT Broker(用轻量的Mosquitto模拟),实现:
- 智能灯(Publisher):周期性发布自身状态(开关/亮度),同时订阅控制指令;
- 网关(Broker):Mosquitto服务,负责消息路由;
- 手机APP(Subscriber):订阅智能灯状态、接收消息,也可发布控制指令。
环境准备
- 安装依赖:
pip install paho-mqtt(MQTT客户端库); - 安装Mosquitto(模拟网关Broker):
- Windows:下载安装包,启动服务
net start mosquitto; - Linux:
sudo apt install mosquitto && sudo systemctl start mosquitto; - 验证:默认监听1883端口,
telnet localhost 1883可连通。
- Windows:下载安装包,启动服务
二、代码实现
1. 智能灯(Publisher):light_publisher.py
核心逻辑:发布状态Topic(home/light/status),订阅控制Topic(home/light/control),模拟灯的状态上报和指令接收。
import paho.mqtt.client as mqtt
import time
import random
# MQTT Broker配置(网关地址,本地模拟则为localhost)
BROKER_HOST = "localhost"
BROKER_PORT = 1883
CLIENT_ID = "smart_light_001" # 智能灯唯一标识
# 灯的初始状态
light_status = {
"switch": "on",
"brightness": 80
}
# 连接Broker成功的回调
def on_connect(client, userdata, flags, rc):
print(f"智能灯连接网关Broker成功,返回码:{rc}")
# 订阅控制指令Topic(QoS 1,确保指令不丢失)
client.subscribe("home/light/control", qos=1)
# 接收控制指令的回调(订阅者逻辑)
def on_message(client, userdata, msg):
cmd = msg.payload.decode("utf-8")
print(f"\n收到控制指令:{cmd}")
# 模拟执行指令
if cmd == "off":
light_status["switch"] = "off"
light_status["brightness"] = 0
elif cmd == "on":
light_status["switch"] = "on"
light_status["brightness"] = 80
elif cmd.startswith("brightness:"):
light_status["brightness"] = int(cmd.split(":")[1])
print(f"灯状态更新:{light_status}")
# 初始化客户端
client = mqtt.Client(client_id=CLIENT_ID, clean_session=False)
client.on_connect = on_connect
client.on_message = on_message
# 连接Broker
client.connect(BROKER_HOST, BROKER_PORT, keepalive=60)
# 启动客户端循环(处理网络事件)
client.loop_start()
# 周期性发布灯的状态(QoS 1,确保状态送达)
try:
while True:
status_msg = f"{light_status['switch']},{light_status['brightness']}"
client.publish("home/light/status", payload=status_msg, qos=1)
print(f"发布灯状态:{status_msg}")
time.sleep(5) # 每5秒发布一次
except KeyboardInterrupt:
print("\n智能灯断开连接")
client.loop_stop()
client.disconnect()
2. 手机APP(Subscriber):phone_subscriber.py
核心逻辑:订阅状态Topic接收灯的状态,手动输入指令发布控制消息。
import paho.mqtt.client as mqtt
import time
# MQTT Broker配置
BROKER_HOST = "localhost"
BROKER_PORT = 1883
CLIENT_ID = "phone_app_001" # 手机APP唯一标识
# 连接Broker成功的回调
def on_connect(client, userdata, flags, rc):
print(f"手机APP连接网关Broker成功,返回码:{rc}")
# 订阅灯状态Topic(QoS 1)
client.subscribe("home/light/status", qos=1)
# 接收灯状态的回调
def on_message(client, userdata, msg):
status = msg.payload.decode("utf-8")
switch, brightness = status.split(",")
print(f"\n【灯状态更新】开关:{switch},亮度:{brightness}%")
# 初始化客户端
client = mqtt.Client(client_id=CLIENT_ID, clean_session=False)
client.on_connect = on_connect
client.on_message = on_message
# 连接Broker
client.connect(BROKER_HOST, BROKER_PORT, keepalive=60)
# 启动客户端循环
client.loop_start()
# 手动输入控制指令
try:
while True:
print("\n===== 控制指令 =====")
print("输入 off/on 控制开关,输入 brightness:数值 调节亮度(如brightness:50)")
cmd = input("请输入指令(回车发送):")
if cmd:
# 发布控制指令(QoS 1)
client.publish("home/light/control", payload=cmd, qos=1)
print(f"已发送指令:{cmd}")
time.sleep(0.5)
except KeyboardInterrupt:
print("\n手机APP断开连接")
client.loop_stop()
client.disconnect()
3. 网关Broker:启动Mosquitto
无需代码,直接启动Mosquitto服务(模拟网关内置Broker):
# Windows
mosquitto.exe -c mosquitto.conf # 或直接net start mosquitto
# Linux
sudo systemctl start mosquitto
默认配置即可,无需额外修改(家用网关内置Broker会默认开启1883端口、基础权限)。
三、交互时序图(Mermaid语法)
以下是智能灯发布状态 + 手机APP接收状态 + 手机发布控制指令 + 智能灯执行 的完整时序(以QoS 1为例,保证消息至少一次送达):
四、运行说明
- 先启动Mosquitto(网关Broker);
- 运行
light_publisher.py(智能灯上线,开始发布状态); - 运行
phone_subscriber.py(手机APP上线,接收状态,可输入指令控制); - 效果:
- 手机APP实时接收灯的状态;
- 输入
off,智能灯关闭,状态更新为off,0并发布,手机同步接收; - 输入
brightness:50,智能灯亮度改为50,状态同步到手机。
五、关键细节说明
- QoS 1的核心体现:每个PUBLISH消息都有PUBACK确认,确保消息至少送达一次;
- 角色复用:智能灯既是Publisher(发布状态)也是Subscriber(订阅控制),手机同理;
- 网关Broker的作用:
- 验证客户端连接身份(示例简化了认证,实际网关会有设备白名单/密钥);
- 路由消息(状态消息从智能灯→Broker→手机,控制指令从手机→Broker→智能灯);
- 缓存消息(若智能灯离线,Broker会缓存控制指令,重连后推送)。
报文详解
一、MQTT报文基础结构(先铺垫核心规则)
MQTT协议基于二进制报文通信,所有交互报文由三部分组成,这是解析所有报文的基础:
| 报文部分 | 作用 | 核心字段 |
|---|---|---|
| 固定头(必选) | 标识报文类型、QoS、重传标志(Dup)、保留标志(Retain),占2字节起步 | 第1字节:报文类型(4位) + Dup(1位) + QoS(2位) + Retain(1位);第2字节:剩余长度(后续字节数,可变) |
| 可变头(可选) | 随报文类型变化,存储协议版本、Topic、消息ID(MsgID)等核心元数据 | 如CONNECT含协议名/版本,PUBLISH含Topic+MsgID(QoS≥1时) |
| 有效载荷(可选) | 实际数据,如客户端ID、消息内容、订阅Topic列表等 | 如PUBLISH的有效载荷是“on,80”,CONNECT的有效载荷是客户端ID+密码 |
关键编码规则:
- 报文类型编码(4位):CONNECT=1、CONNACK=2、PUBLISH=3、PUBACK=4、SUBSCRIBE=8、SUBACK=9、DISCONNECT=14;
- 剩余长度:采用“可变长度编码”(1~4字节),表示“可变头+有效载荷”的总字节数;
- MsgID:仅QoS≥1的PUBLISH/PUBACK/SUBSCRIBE等报文携带(16位无符号整数,0~65535),用于标识消息、实现重传/确认。
二、完整交互报文详解(基于代码场景:智能灯+网关Broker+手机APP)
以下所有报文均对应代码中的实际交互(Broker地址localhost:1883,智能灯ClientID=smart_light_001,手机ClientID=phone_app_001,QoS=1),按“连接→订阅→发布/接收→断开”流程拆解。
阶段1:客户端连接Broker(CONNECT/CONNACK)
1.1 智能灯→Broker:CONNECT报文(发起连接)
# 代码对应:client.connect(BROKER_HOST, BROKER_PORT, keepalive=60)
报文二进制解析(示例):
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0x10 0x27 | 0x10 = 报文类型(0001=CONNECT) + Dup(0) + QoS(00) + Retain(0); 0x27 = 剩余长度(39字节,即后续可变头+有效载荷共39字节) |
| 可变头 | 0x00 0x04 4D 51 54 54 0x04 0x02 0x00 0x3C | 0x00 0x04 4D515454:协议名长度(4) + “MQTT”; 0x04:MQTT版本(4=MQTT 3.1.1); 0x02:连接标志(清理会话=0+遗嘱=0+用户名=0+密码=0+保活时间=1); 0x00 0x3C:保活时间(60秒) |
| 有效载荷 | 0x00 0x0B 73 6D 61 72 74 5F 6C 69 67 68 74 5F 30 30 31 | 0x00 0x0B:客户端ID长度(11); 736D6172745F6C696768745F303031:“smart_light_001”(ASCII编码) |
核心含义:智能灯向Broker发起连接,声明使用MQTT 3.1.1协议、保活时间60秒、客户端ID为smart_light_001(代码中clean_session=False,对应连接标志的“清理会话位=0”,Broker会保留订阅关系)。
1.2 Broker→智能灯:CONNACK报文(连接确认)
报文二进制解析(示例):
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0x20 0x02 | 0x20 = 报文类型(0010=CONNACK) + Dup(0) + QoS(00) + Retain(0); 0x02 = 剩余长度(2字节) |
| 可变头 | 0x00 0x00 | 0x00:连接确认标志(无会话保留); 0x00:返回码(0=连接成功,其他值为失败,如1=协议版本不支持) |
| 有效载荷 | 无 | - |
核心含义:Broker确认智能灯连接成功(返回码0),手机APP连接Broker的CONNACK报文结构完全一致,仅客户端ID不同。
阶段2:客户端订阅Topic(SUBSCRIBE/SUBACK)
2.1 智能灯→Broker:SUBSCRIBE报文(订阅控制指令Topic)
# 代码对应:client.subscribe("home/light/control", qos=1)
报文二进制解析(示例):
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0x82 0x13 | 0x82 = 报文类型(1000=SUBSCRIBE) + Dup(0) + QoS(01=1) + Retain(0); 0x13 = 剩余长度(19字节) |
| 可变头 | 0x00 0x01 | 0x00 0x01:MsgID(1,SUBSCRIBE必须带MsgID,用于匹配SUBACK) |
| 有效载荷 | 0x00 0x10 68 6F 6D 65 2F 6C 69 67 68 74 2F 63 6F 6E 74 72 6F 6C 0x01 | 0x00 0x10:Topic长度(16); 686F6D652F6C696768742F636F6E74726F6C:“home/light/control”; 0x01:订阅QoS(1) |
2.2 Broker→智能灯:SUBACK报文(订阅确认)
报文二进制解析(示例):
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0x90 0x03 | 0x90 = 报文类型(1001=SUBACK) + Dup(0) + QoS(00) + Retain(0); 0x03 = 剩余长度(3字节) |
| 可变头 | 0x00 0x01 | 0x00 0x01:MsgID(与SUBSCRIBE的MsgID一致,1) |
| 有效载荷 | 0x01 | 0x01:订阅结果(Broker确认的QoS等级,1=与请求一致) |
核心含义:Broker确认智能灯成功订阅home/light/control(QoS=1);手机APP订阅home/light/status的SUBSCRIBE/SUBACK报文结构完全一致,仅Topic和MsgID不同。
阶段3:发布/接收消息(PUBLISH/PUBACK,QoS=1)
3.1 智能灯→Broker:发布灯状态PUBLISH报文
# 代码对应:client.publish("home/light/status", payload="on,80", qos=1)
报文二进制解析(示例):
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0x32 0x0F | 0x32 = 报文类型(0011=PUBLISH) + Dup(0) + QoS(01=1) + Retain(0); 0x0F = 剩余长度(15字节) |
| 可变头 | 0x00 0x0E 68 6F 6D 65 2F 6C 69 67 68 74 2F 73 74 61 74 75 73 0x00 0x02 | 0x00 0x0E:Topic长度(14); 686F6D652F6C696768742F737461747573:“home/light/status”; 0x00 0x02:MsgID(2,QoS≥1必须带) |
| 有效载荷 | 6F 6E 2C 38 30 | 6F6E2C3830:“on,80”(ASCII编码) |
3.2 Broker→智能灯:PUBACK报文(确认接收状态消息)
报文二进制解析(示例):
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0x40 0x02 | 0x40 = 报文类型(0100=PUBACK) + Dup(0) + QoS(00) + Retain(0); 0x02 = 剩余长度(2字节) |
| 可变头 | 0x00 0x02 | 0x00 0x02:MsgID(与PUBLISH的MsgID一致,2) |
| 有效载荷 | 无 | - |
3.3 Broker→手机APP:转发状态PUBLISH报文
Broker收到智能灯的状态消息后,向订阅了home/light/status的手机APP转发PUBLISH报文,结构与3.1完全一致(仅Dup/MsgID可能重新分配,示例MsgID=3):
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0x32 0x0F | 0x32 = PUBLISH + Dup(0) + QoS(1) + Retain(0); 0x0F = 剩余长度15 |
| 可变头 | 0x00 0x0E + Topic + 0x00 0x03 | Topic=home/light/status,MsgID=3 |
| 有效载荷 | 6F 6E 2C 38 30 | “on,80” |
3.4 手机APP→Broker:PUBACK报文(确认接收状态)
与3.2结构一致,仅MsgID=3:
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0x40 0x02 | PUBACK + 剩余长度2 |
| 可变头 | 0x00 0x03 | MsgID=3(匹配转发的PUBLISH) |
3.5 手机APP→Broker:发布控制指令PUBLISH报文(如“brightness:50”)
# 代码对应:client.publish("home/light/control", payload="brightness:50", qos=1)
报文二进制解析(示例):
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0x32 0x16 | 0x32 = PUBLISH + Dup(0) + QoS(1) + Retain(0); 0x16 = 剩余长度22 |
| 可变头 | 0x00 0x10 + Topic + 0x00 0x04 | Topic=home/light/control,MsgID=4 |
| 有效载荷 | 62 72 69 67 68 74 6E 65 73 73 3A 35 30 | “brightness:50”(ASCII编码) |
3.6 Broker→智能灯:转发控制指令PUBLISH报文
结构与3.5一致(MsgID=5),智能灯接收后返回PUBACK(MsgID=5),完成指令交付。
阶段4:断开连接(DISCONNECT)
# 代码对应:client.disconnect()
4.1 智能灯→Broker:DISCONNECT报文
报文二进制解析(示例):
| 部分 | 二进制(十六进制) | 字段解析 |
|---|---|---|
| 固定头 | 0xE0 0x00 | 0xE0 = 报文类型(1110=DISCONNECT) + Dup(0) + QoS(00) + Retain(0); 0x00 = 剩余长度0(无可变头/有效载荷) |
| 可变头 | 无 | - |
| 有效载荷 | 无 | - |
核心含义:智能灯主动向Broker发送断开连接指令,Broker收到后释放连接资源;手机APP的DISCONNECT报文结构完全一致。
三、关键报文规则补充(结合代码场景)
- QoS=1的核心保障:所有PUBLISH报文均带MsgID,且必须收到对应PUBACK才会终止重传(代码中若Broker未返回PUBACK,智能灯会超时重传,此时Dup标志置1);
- Retain标志:代码中
publish未设置retain=True,所以固定头的Retain位为0(若置1,Broker会保留该Topic的最后一条消息,新订阅者上线直接收到); - 剩余长度编码:若“可变头+有效载荷”超过127字节,剩余长度会用多字节编码(如128字节=0x80 0x01),代码中消息内容短,仅用1字节即可;
- Dup标志:仅重传时置1(如智能灯发布消息后超时未收到PUBACK,重传PUBLISH时Dup=1,MsgID不变)。
四、报文交互核心逻辑总结
智能灯→Broker:CONNECT → Broker→智能灯:CONNACK
智能灯→Broker:SUBSCRIBE → Broker→智能灯:SUBACK
手机APP→Broker:CONNECT → Broker→手机APP:CONNACK
手机APP→Broker:SUBSCRIBE → Broker→手机APP:SUBACK
智能灯→Broker:PUBLISH(状态) → Broker→智能灯:PUBACK
Broker→手机APP:PUBLISH(状态) → 手机APP→Broker:PUBACK
手机APP→Broker:PUBLISH(指令) → Broker→手机APP:PUBACK
Broker→智能灯:PUBLISH(指令) → 智能灯→Broker:PUBACK
智能灯→Broker:DISCONNECT
手机APP→Broker:DISCONNECT
所有报文均遵循“固定头+可变头+有效载荷”结构,QoS=1通过“PUBLISH+PUBACK”两次交互保证消息至少送达一次,这也是代码中能稳定收发消息的核心原因。

浙公网安备 33010602011771号