关键词MQTT协议物联网通信发布订阅QoSBrokerMQTT5「知识图谱生成工具」一键将文件夹内容变身为交互式知识图谱的免安装桌面工具文末附免费下载链接-CSDN博客CSDN AI数字营销功能实测CSDN AI内容创作10分钟从技术选题到成文技术博主最值得开通的功能没有之一-CSDN博客一句话总结MQTT是物联网世界的小区公告栏——有人贴通知发布想看的人去看订阅不用挨家挨户敲门。它用极低的带宽和功耗让数以亿计的物联网设备高效对话。一、MQTT是什么——从挨家敲门到公告栏想象一下你住在一个有1000户的小区里。某天物业要通知大家停水维修有两种做法HTTP方式挨家敲门物业挨家挨户敲门每户都要开门确认耗时耗力还有人不在家连接失败。MQTT方式公告栏物业直接在小区公告栏贴通知想看的业主自己去看不想看的也不用管。核心比喻MQTT就像小区的公告栏——有人贴通知发布想看的人去看订阅不用挨家挨户敲门。这就是发布/订阅模式的精髓。MQTTMessage Queuing Telemetry Transport消息队列遥测传输是IBM在1999年开发的协议2014年成为OASIS标准。它的设计初衷很简单让带宽极低、功耗敏感、网络不稳定的设备也能可靠通信。典型的MQTT应用场景包括智能家居温湿度传感器、智能灯泡工业物联网设备状态监控、预测性维护车联网车辆定位、远程控制环境监测空气质量、水质监测即时通讯微信部分功能、Facebook Messenger二、MQTT架构模型——三个核心角色MQTT的架构非常简单只有三个核心角色2.1 发布者Publisher负责贴通知的设备或应用。比如温度传感器每隔5分钟发布一次当前温度。发布者只负责发不关心谁收。2.2 订阅者Subscriber负责看公告的设备或应用。比如手机App订阅了客厅温度主题就能收到温度数据。订阅者只关心自己感兴趣的主题。2.3 Broker消息代理/服务器这是整个系统的公告栏管理员。它接收所有发布者的消息并根据订阅关系分发给对应的订阅者。Broker是MQTT架构的核心所有消息都经过它中转。┌─────────────────────────────────────────────────────────────┐ │ MQTT 架构示意图 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────────┐ ┌─────────┐ │ │ │ 温度传感器 │────────▶│ │────────▶│ 手机App │ │ │ │(Publisher)│ │ │ │(Subscriber)│ │ └──────────┘ │ │ └─────────┘ │ │ │ Broker │ │ │ ┌──────────┐ │ (消息代理) │ ┌─────────┐ │ │ │ 智能灯泡 │────────▶│ │────────▶│ 智能音箱 │ │ │ │(Publisher)│ │ │ │(Subscriber)│ │ └──────────┘ │ │ └─────────┘ │ │ └──────────────┘ │ │ ▲ │ │ ┌──────────┐ │ │ │ │ 门禁系统 │───────────────┘ │ │ │(Publisher)│ │ │ └──────────┘ │ │ │ │ 发布者只管发 ───────▶ Broker统一中转 ───────▶ 订阅者按需接收 │ │ │ └─────────────────────────────────────────────────────────────┘2.4 Topic主题——消息的分类标签Topic是MQTT中最重要的概念之一它就像公告栏上的分类标签。消息按照Topic组织订阅者按Topic过滤自己感兴趣的消息。Topic使用层级结构用斜杠/分隔home/livingroom/temperature # 客厅温度 home/bedroom/humidity # 卧室湿度 factory/machine1/status # 1号机器状态 city/beijing/airquality # 北京空气质量Topic支持两种通配符单层通配符匹配一个层级。如home//temperature匹配所有房间的温度。#多层通配符匹配多个层级必须是Topic末尾。如home/#匹配家里所有设备。三、MQTT报文格式——解剖一个数据包MQTT协议之所以轻量很大程度上得益于其精简的报文格式。一个MQTT报文由三部分组成┌─────────────────────────────────────────────────────────────┐ │ MQTT 报文结构 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────┬────────────────┬──────────────────────┐ │ │ │ 固定报头 │ 可变报头 │ 有效载荷 │ │ │ │ (Fixed Header) │ (Variable Header)│ (Payload) │ │ │ ├────────────────┼────────────────┼──────────────────────┤ │ │ │ • 报文类型 │ • 协议名称 │ • 实际消息内容 │ │ │ │ • 标志位 │ • 协议级别 │ • 主题名(某些类型) │ │ │ │ • 剩余长度 │ • 连接标志 │ • 用户名密码等 │ │ │ │ │ • 保活时间 │ │ │ │ │ │ • 报文标识符 │ │ │ │ └────────────────┴────────────────┴──────────────────────┘ │ │ │ │ 固定报头2-5字节 可变报头0-几KB 有效载荷0-几百MB │ │ │ └─────────────────────────────────────────────────────────────┘3.1 固定报头Fixed Header每个MQTT报文都必须有固定报头最少2字节位7-43210字节1报文类型 (4 bits)标志位 (4 bits)字节2-5剩余长度变长编码最多4字节报文类型定义了MQTT支持的操作CONNECT(1)客户端请求连接CONNACK(2)连接确认PUBLISH(3)发布消息PUBACK(4)发布确认QoS 1PUBREC(5)发布收到QoS 2PUBREL(6)发布释放QoS 2PUBCOMP(7)发布完成QoS 2SUBSCRIBE(8)订阅请求SUBACK(9)订阅确认UNSUBSCRIBE(10)取消订阅UNSUBACK(11)取消订阅确认PINGREQ(12)心跳请求PINGRESP(13)心跳响应DISCONNECT(14)断开连接3.2 可变报头Variable Header某些报文类型需要额外的信息比如CONNECT报文协议名(“MQTT”)、协议级别(4或5)、连接标志、保活时间PUBLISH报文主题名、报文标识符QoS0时SUBSCRIBE报文报文标识符3.3 有效载荷Payload这是真正要传输的数据。比如PUBLISH报文的有效载荷就是消息内容CONNECT报文可能包含客户端ID、用户名、密码等。为什么MQTT轻量对比HTTPMQTT的报文头最小只有2字节而HTTP头动辄几百字节。在带宽只有几KB/s的NB-IoT网络中这个差距就是能用和不能用的区别。四、QoS等级详解——快递的三种寄法QoSQuality of Service服务质量是MQTT保证消息可靠性的机制。它就像寄快递有三种选择QoS就像寄快递QoS 0 平邮可能丢QoS 1 挂号信一定到但可能重复QoS 2 保价快递保证只到一次4.1 QoS 0最多一次At most once特点发完就忘不保证送达不确认。适用场景高频上报、可容忍丢失的数据如温度传感器每5分钟上报一次。报文交互只有PUBLISH没有确认。┌─────────────────────────────────────────────────────────────┐ │ QoS 0 交互流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Publisher Broker │ │ │ │ │ │ │ ─────── PUBLISH ───────────▶ │ │ │ │ │ │ │ │ (发完就忘不管了) │ │ │ │ │ │ │ │ │ 特点只发一次无确认可能丢失开销最小 │ │ │ └─────────────────────────────────────────────────────────────┘4.2 QoS 1至少一次At least once特点保证送达但可能重复。适用场景需要确保收到但可容忍重复的数据如开关控制指令。报文交互PUBLISH → PUBACK┌─────────────────────────────────────────────────────────────┐ │ QoS 1 交互流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Publisher Broker │ │ │ │ │ │ │ ─────── PUBLISH ───────────▶ │ │ │ │ │ │ │ │ ◀──────── PUBACK ─────────── │ │ │ │ │ │ │ │ (没收到PUBACK就重发) │ │ │ │ │ │ │ │ │ 特点保证送达可能重复一次往返确认 │ │ │ └─────────────────────────────────────────────────────────────┘4.3 QoS 2恰好一次Exactly once特点保证送达且不重复最可靠但开销最大。适用场景绝对不能重复的关键数据如支付指令、重要告警。报文交互PUBLISH → PUBREC → PUBREL → PUBCOMP四次握手┌─────────────────────────────────────────────────────────────┐ │ QoS 2 交互流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Publisher Broker │ │ │ │ │ │ │ ─────── PUBLISH ───────────▶ │ │ │ │ │ │ │ │ ◀──────── PUBREC ─────────── │ (收到暂存) │ │ │ │ │ │ │ ─────── PUBREL ────────────▶ │ (可以释放) │ │ │ │ │ │ │ ◀──────── PUBCOMP ────────── │ (完成) │ │ │ │ │ │ │ │ 特点四次握手保证恰好一次开销最大 │ │ │ └─────────────────────────────────────────────────────────────┘4.4 QoS选择建议QoS等级可靠性开销适用场景0低最小传感器数据、心跳包1中中等控制指令、状态通知2高最大支付、关键告警⚠️注意QoS是端到端的发布者和订阅者可以设置不同的QoS。最终生效的是两者中较低的那个。比如发布者发QoS 2订阅者只支持QoS 1那实际就是QoS 1。五、遗嘱消息与保留消息——两个实用特性5.1 Last Will遗嘱消息想象一个场景你的智能门锁突然断网了你希望能及时知道它掉线了。这就是遗嘱消息的用途。遗嘱消息是客户端在连接时预先设置好的遗言。当客户端异常断开不是正常DISCONNECT时Broker会自动发布这条消息。遗嘱消息包含Will Topic遗嘱主题Will Message遗嘱内容Will QoS遗嘱的QoS等级Will Retain是否保留# 连接时设置遗嘱 CONNECT Will Topic: device/lock001/status Will Message: offline Will QoS: 1 Will Retain: true # 正常工作时 PUBLISH device/lock001/status online (Retaintrue) # 异常断开如断电、断网 # Broker自动发布 PUBLISH device/lock001/status offline5.2 Retained Message保留消息保留消息是Broker会记住的最后一条消息。新订阅者上线时会立即收到这条保留消息不用等发布者下次发送。典型应用设备状态新订阅者立即知道设备是在线还是离线配置信息新设备上线立即获取最新配置最新数据新订阅者立即看到最新的传感器读数最佳实践通常把遗嘱消息和保留消息配合使用。设备上线时发布带Retain的状态online设置遗嘱为offline也是Retain。这样任何订阅者都能立即知道设备的真实状态。六、MQTT vs HTTP——物联网场景下的降维打击很多人问为什么不用HTTPREST API不香吗在物联网场景下MQTT对HTTP简直是降维打击对比项MQTTHTTP连接方式长连接TCP保持短连接每次请求新建TCP报文头大小2字节起步几百字节起步消息推送原生支持订阅需要轮询或WebSocket功耗低可保持休眠高频繁建连带宽占用极低较高实时性毫秒级秒级轮询或毫秒级WebSocketQoS保证内置0/1/2三级需应用层实现离线消息原生支持需额外实现适用场景IoT、实时推送Web、API具体数据对比发送1KB数据MQTT报文头约2-5字节总流量约1.005KBHTTP请求头约200-800字节总流量约1.2-1.8KB在NB-IoT等窄带网络中MQTT的带宽优势可能意味着设备能多工作几个月电池寿命。七、MQTT5新特性——协议的进化MQTT 5.0于2019年发布带来了许多实用的新特性。以下是几个最重要的7.1 用户属性User Properties可以在报文中携带自定义的键值对就像HTTP的Header。这大大增强了协议的扩展性。# MQTT5可以在PUBLISH中添加自定义属性 PUBLISH Topic: home/temperature Payload: 25.3 User Properties: - unit: celsius - sensor_id: temp_001 - location: living_room7.2 共享订阅Shared Subscriptions多个客户端可以组成一个订阅组消息只会被组内一个客户端接收。这实现了负载均衡。# 共享订阅格式$share/{group}/{topic} $share/group1/sensors//temperature # 客户端A和B都订阅上面的主题 # 当有新消息时只会发给A或B中的一个而不是两个都发7.3 流量控制Flow Control客户端可以告知Broker自己能处理的最大消息数Receive Maximum防止被消息淹没。7.4 其他重要特性主题别名Topic Alias用数字代替长主题名减少重复传输消息过期Message Expiry设置消息有效期过期自动丢弃会话过期Session Expiry控制离线会话保留时间原因码Reason Code更详细的错误信息服务端分配ClientID客户端可以请求Broker分配ID八、Python实战——用paho-mqtt玩转MQTT下面是用Python的paho-mqtt库实现完整MQTT通信的代码示例。8.1 安装依赖pip install paho-mqtt8.2 发布者代码Publisherimport paho.mqtt.client as mqtt import json import time import random # MQTT Broker配置 BROKER broker.hivemq.com # 公共测试Broker PORT 1883 TOPIC iot/demo/temperature # 连接回调 def on_connect(client, userdata, flags, rc): if rc 0: print(✅ 连接成功) else: print(f❌ 连接失败错误码: {rc}) # 创建客户端 client mqtt.Client() client.on_connect on_connect # 设置遗嘱消息异常断开时发送 client.will_set(TOPIC, payloadjson.dumps({status: offline}), qos1, retainTrue) # 连接Broker print(f正在连接 {BROKER}:{PORT}...) client.connect(BROKER, PORT, keepalive60) # 启动网络循环 client.loop_start() try: # 发布在线状态保留消息 client.publish(TOPIC, payloadjson.dumps({status: online}), qos1, retainTrue) # 模拟发送温度数据 for i in range(10): temp round(20 random.random() * 10, 1) humidity round(40 random.random() * 30, 1) payload { device_id: sensor_001, temperature: temp, humidity: humidity, timestamp: time.time() } result client.publish(TOPIC, payloadjson.dumps(payload), qos1) if result.rc mqtt.MQTT_ERR_SUCCESS: print(f 发送成功: 温度{temp}°C, 湿度{humidity}%) else: print(f 发送失败) time.sleep(2) except KeyboardInterrupt: print(\n 停止发送) finally: # 正常断开 client.publish(TOPIC, payloadjson.dumps({status: disconnected}), qos1, retainTrue) client.loop_stop() client.disconnect() print( 已断开连接)8.3 订阅者代码Subscriberimport paho.mqtt.client as mqtt import json # MQTT Broker配置 BROKER broker.hivemq.com PORT 1883 TOPIC iot/demo/temperature # 连接回调 def on_connect(client, userdata, flags, rc): if rc 0: print(✅ 连接成功) # 订阅主题 client.subscribe(TOPIC, qos1) print(f 已订阅主题: {TOPIC}) else: print(f❌ 连接失败错误码: {rc}) # 消息接收回调 def on_message(client, userdata, msg): try: payload json.loads(msg.payload.decode()) # 处理不同类型的消息 if status in payload: print(f 设备状态: {payload[status]}) elif temperature in payload: print(f 收到数据: 温度{payload[temperature]}°C, f湿度{payload[humidity]}%, f设备{payload[device_id]}) else: print(f 收到消息: {payload}) except json.JSONDecodeError: print(f 收到原始消息: {msg.payload.decode()}) # 断开连接回调 def on_disconnect(client, userdata, rc): if rc ! 0: print(f⚠️ 异常断开错误码: {rc}) # 创建客户端 client mqtt.Client() client.on_connect on_connect client.on_message on_message client.on_disconnect on_disconnect # 连接Broker print(f正在连接 {BROKER}:{PORT}...) client.connect(BROKER, PORT, keepalive60) # 阻塞运行等待消息 print( 等待消息... (按CtrlC退出)) try: client.loop_forever() except KeyboardInterrupt: print(\n 停止接收) client.disconnect() print( 已断开连接)8.4 运行测试先启动订阅者python subscriber.py再启动发布者python publisher.py观察订阅者输出应该能看到实时接收到的温度数据。8.5 常用MQTT Broker推荐Broker特点适用场景Eclipse Mosquitto轻量、开源、C语言实现嵌入式、边缘设备EMQ X企业级、高并发、功能丰富大规模IoT平台HiveMQ企业级、商业支持企业生产环境VerneMQ分布式、高可用大规模集群部署broker.hivemq.com公共测试Broker学习测试 源码获取本文完整代码已上传GitHub包含Publisher/Subscriber完整示例带SSL/TLS加密的连接示例遗嘱消息和保留消息示例QoS 0/1/2对比测试代码GitHub地址https://github.com/yourname/mqtt-tutorial 思考题如果你的物联网设备使用电池供电且每天只能发送100次数据你会选择什么QoS等级为什么设计一个智能家居场景说明如何使用遗嘱消息和保留消息来实现设备状态监控。MQTT5的共享订阅功能在什么场景下特别有用请举一个实际例子。对比MQTT和WebSocket在什么情况下你会选择MQTT而不是WebSocket 系列文章预告《网络协议深度解析》系列持续更新中下一篇《CoAP协议详解——MQTT的轻量级对手》敬请期待《WebSocket实战——从HTTP升级到全双工通信》敬请期待《gRPC入门——高性能RPC框架》敬请期待《QUIC协议——下一代HTTP/3的基石》关注专栏第一时间获取更新标签MQTT | 物联网 | IoT | 消息队列 | 嵌入式如果本文对你有帮助欢迎点赞、收藏⭐、评论你的支持是我持续创作的动力