# MQTT 协议详解：发布/订阅模型、三级 QoS 与 5.0 新特性

**URL:** <https://bbs.eeclub.top/t/topic/401>\
**Category:** 教程与文档 / Tutorials & Documents\
**Tags:** IoT, MQTT\
**Created:** [2026 年7 月 23 日 13:55 UTC](https://bbs.eeclub.top/t/topic/401 "2026-07-23T13:55:22Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

作者： ![zeruns](https://bbs.eeclub.top/user_avatar/bbs.eeclub.top/zeruns/32/7_2.png) [@zeruns](https://bbs.eeclub.top/u/zeruns)\
发布日期： [2026 年7 月 23 日 13:55 UTC](https://bbs.eeclub.top/t/topic/401/1 "2026-07-23T13:55:22Z")

</div>

如果做过物联网项目，大概率绕不开一个词：MQTT。从家里的智能灯泡到田间的土壤传感器，从产线上的机床到路边的共享单车，数十亿台设备正靠这个诞生于 1999 年的协议彼此通信。它凭什么成了物联网的事实标准？和 HTTP 比到底强在哪？这篇文章会从发布/订阅模型讲到 QoS 三级、遗嘱消息、MQTT 5.0 新特性，再配上协议对比和一段能直接跑的 Python 代码，帮你一次性把 MQTT 捋清楚。

![](https://tc2.zeruns.com/tc/2026/07/23/ChatGPT-Image-2026723-18_22_54255f6d21e269386c.jpg)

## 一、从一个智能大棚说起：为什么物联网不能只用 HTTP

想象一个典型的智能农业大棚：几百个温湿度、光照、土壤墒情传感器散落田间，靠电池和太阳能板供电，通过时好时坏的 4G 网络把数据上报到云端；云端则要根据实时数据，远程控制卷帘、风机和灌溉阀门。

方案评审时，开发团队的第一反应往往是："用 HTTP 呗，POST 一下不就完了。"思路没错，但到了弱网环境、设备成百上千、还要 7×24 小时在线的真实场景里，HTTP 的短板会全部暴露：

- **云端没法主动推** 。HTTP 是请求/响应模式，云端想下发一条"开风机降温"的指令，只能等设备下次轮询。轮询间隔长了，指令延迟感人；间隔短了，几千台设备一起轮询，服务器和网络直接被无谓的请求打满。
- **头部开销太大** 。一次 HTTP 请求光头部就可能几百字节，而设备真正要传的数据可能只有十几个字节——比如一个温度值"26.5"，好比用快递大纸箱寄一张纸条。
- **功耗顶不住** 。每次通信都要完整的 TCP + TLS 握手，对电池供电的传感器来说，射频模块多工作一秒都是在烧钱。

这不只是农业场景的麻烦，更是整个物联网行业的共性问题： **海量设备、弱网环境、低功耗约束、双向实时通信** 。HTTP 是为人浏览网页设计的，不是为机器之间唠嗑设计的。而 MQTT，恰恰为此而生。

## 二、MQTT 是什么：一个为"省钱"而生的协议

MQTT 最早是 **Message Queuing Telemetry Transport** （消息队列遥测传输）的缩写。不过如今官方已不再把它当缩写解释——协议内部其实没有传统意义上的消息队列，这个名字更多是历史遗留。

它的出身很能说明问题。1999 年，IBM 的 Andy Stanford-Clark 和 Arcom 公司的 Arlen Nipper 设计了这个协议，当时的场景是： **通过卫星链路监控横跨荒原的石油管道** 。卫星通信按流量计费、带宽极窄、延迟高，沿线监测设备又靠电池供电。于是设计目标非常朴素：报文要小、协议要省电、网络断了也得扛得住。

这三个朴素目标，塑造了 MQTT 延续至今的基因：

- **报文极小** ：固定报头最小只有 2 个字节，对比 HTTP 动辄几百字节的文本头部，省到了极致。
- **轻量** ：跑在 TCP 之上（默认端口 1883，TLS 加密为 8883），单片机几十 KB 内存就能跑一个 MQTT 客户端。
- **为不稳定网络设计** ：内置心跳、遗嘱、分级 QoS 等一整套"断线自保"机制。

2013 年前后 IBM 将 MQTT 提交给 OASIS 标准组织，2014 年 MQTT 3.1.1 成为 OASIS 正式标准，后来被接纳为 ISO 国际标准（ISO/IEC 20922）。目前主流版本是 **MQTT 3.1.1** 和 **MQTT 5.0** （2019 年发布），5.0 是现在的推荐版本，后文会专门聊它。

**eeClub-电子工程师社区：[https://bbs.eeclub.top/](https://bbs.eeclub.top/)**

**电子/单片机技术交流QQ群： [2169025065](https://qm.qq.com/q/haWR2WfhIc)**

## 三、核心架构：不是"打电话"，而是"订报纸"

理解 MQTT，最关键的是理解它的通信模型—— **发布/订阅模式（Publish/Subscribe）** 。

HTTP 的请求/响应模式像 **打电话** ：你拨通对方号码直接对话，双方必须同时在线，且互相知道对方的"号码"。

发布/订阅模式则像 **订报纸** ：报社（发布者）印好报纸送到邮局（Broker），你（订阅者）提前在邮局登记"我订了科技版"，每天报纸一到，邮局就按登记名单投递。报社不知道读者是谁，读者也不需要知道报社的电话—— **双方彻底解耦** ，邮局是唯一的枢纽。

![](https://tc2.zeruns.com/tc/2026/07/23/image-20260723023400891ba639177603e2003.png)

在这个模型里有三个核心角色：

- **Publisher（发布者）** ：产生消息的设备或程序，比如上报温度的传感器。
- **Broker（代理服务器）** ：整个系统的"邮局"，负责接收消息、按主题分发给所有订阅者，还管着连接、会话、保留消息等杂务，是唯一需要公网可达的角色。
- **Subscriber（订阅者）** ：关心某类消息的设备或程序，比如手机 App、数据大盘。

需要说明的是，发布者和订阅者只是逻辑角色，同一台设备完全可以身兼两职——摄像头既向云端发布告警，也订阅云端下发的控制指令。另外，由于设备只需主动向外连接 Broker，自己不需要公网 IP、不需要开放任何端口，天然绕开了 NAT 和防火墙的麻烦。这也是 MQTT 比"设备开端口等连接"之类方案更受欢迎的重要原因。

### Topic：邮局里的"信箱编号"

消息靠什么分发？靠 **Topic（主题）** 。Topic 是一个 UTF-8 字符串，用 `/` 分层，看起来像文件路径：

```auto
home/livingroom/temperature
home/livingroom/humidity
home/bedroom/temperature

```

订阅时可以使用两种 **通配符** ：

- **`+` 单层通配符** ：匹配恰好一层。比如 `home/+/temperature` 能同时收到客厅和卧室的温度。
- **`#` 多层通配符** ：匹配其后的任意多层，只能放在末尾。比如 `home/#` 能收到 home 下的所有消息。

![](https://tc2.zeruns.com/tc/2026/07/23/image-202607230239047644dffe8534f27e834.png)

## 四、关键特性逐个讲透

MQTT 能在弱网环境里立住脚，靠的是一组设计精巧的机制。下面几个特性是面试和实战中最高频的考点。

### 1. QoS：消息投递的三种"快递服务"

MQTT 把消息投递质量（Quality of Service）分成三级，可以理解为三种快递：

- **QoS 0 —— 最多一次（At most once）** ：相当于平邮，发出去就不管了，不确认、不重发。可能丢，但绝不重复。适合高频、丢了也无所谓的数据，比如每秒上报一次的实时值——丢了这帧，下秒还有新的。
- **QoS 1 —— 至少一次（At least once）** ：相当于挂号信。接收方必须回 PUBACK 确认，发送方收不到就重发。保证到达，但 **可能重复** ——确认包在路上丢了，发送方会再寄一封。适合告警、状态变更这类"宁可重复也不能丢"的消息，接收方要做幂等处理。
- **QoS 2 —— 恰好一次（Exactly once）** ：相当于双方签收的专人快递。通过 PUBREC、PUBREL、PUBCOMP 四次握手保证不重不丢，代价是开销最大、速度最慢。适合计费等"多扣一块钱都是事故"的场景。

规律很简单： **QoS 越高，可靠性越强，开销和延迟也越大** ，工程上默认选 QoS 1 往往是最划算的折中。

还有一个容易忽略的细节：QoS 是发布端和订阅端各自声明的，Broker 实际投递时 **取两者的较低值** ——发布方用 QoS 2、而订阅方只订了 QoS 0，消息最终就按 QoS 0 投递。所以排查"为什么我的高 QoS 消息丢了"这类问题时，记得两端都查。

![](https://tc3.zeruns.com/tc/2026/07/23/image-20260723025940327d2df7d3ef6f16bd1.png)

### 2. 保留消息（Retained）：贴在信箱上的便签

普通消息"阅后即焚"——订阅者不在线，消息发完就没了。但发布时设置 **Retain 标志** 后，Broker 会为这个 Topic 保存 **最后一条** 保留消息，之后任何新订阅者一订阅该主题，立刻就能收到它。

典型用法：设备上线后把自己的状态（如"online"、当前开关状态）以 Retained 方式发布。这样无论 App 什么时候打开，都能马上看到设备最新状态，而不必苦等设备下一次上报。注意保留消息每个主题只存一条，新的会覆盖旧的；想清除某个主题的保留消息，向该主题发布一条空载荷的 Retained 消息即可。

### 3. 遗嘱消息（LWT）：设备留下的"遗言"

\*\*Last Will and Testament（遗嘱消息）\*\*是 MQTT 里最有人情味的设计。客户端连接 Broker 时可以提前登记：“如果我死得不明不白（异常掉线），请替我把这条消息发出去。”

比如摄像头连接时登记遗嘱 `camera/01/status = "offline"`（Retained）。一旦设备断电、断网导致连接异常断开，Broker 就会代它发布遗嘱，所有订阅者立刻知道"这台设备挂了"。配合 Retained，后打开 App 的用户也能看到离线状态。

### 4. Keep Alive：心跳，确认彼此还活着

TCP 感知对端"假死"很慢，MQTT 在应用层加了心跳：客户端连接时约定 **Keep Alive** 间隔（比如 60 秒），空闲时就发一个极小的 PINGREQ 报文，Broker 回 PINGRESP。如果 Broker 在 **1.5 倍** Keep Alive 时间内没收到客户端任何消息，就判定其死亡、断开连接，并触发遗嘱消息。

### 5. Clean Session：断线重连后，还记得我吗

客户端通过 **Clean Session** 标志告诉 Broker 要不要保留会话。设为 0（持久会话）时，Broker 会记住这个客户端的订阅关系，以及它离线期间错过的 QoS 1/2 消息，等它重连后补发；设为 1 则重连后一切从零开始。

MQTT 5.0 把这个机制拆成了 **Clean Start** （是否全新开始）和 **Session Expiry Interval** （会话过期时间），表达更精确——比如让会话保留 24 小时，而不是简单的"永存/不存"。

### 6. 报文结构：2 字节起步的极致压缩

MQTT 报文由 **固定报头 + 可变报头 + 有效载荷** 三部分组成。固定报头第一个字节的高 4 位是报文类型（CONNECT、PUBLISH、SUBSCRIBE、PINGREQ 等共 14 种），低 4 位是标志位；之后是变长编码的"剩余长度"字段，最小只占 1 字节。也就是说，一个心跳包总共就 2 个字节——这就是 MQTT"轻"的底气。

![](https://tc2.zeruns.com/tc/2026/07/23/image-20260723031311802392663f2ea0e30f5.png)

## 五、MQTT 5.0：一次诚意满满的升级

2019 年发布的 MQTT 5.0 在保持轻量的前提下补齐了很多工程短板：

- **原因码（Reason Code）** ：几乎所有响应报文都带上了标准化的原因码，连接被拒、订阅失败不再是模糊的"失败"，而是明确告诉你为什么。
- **属性系统（Properties）** ：报文可以携带灵活的元数据键值对，大量新能力都建立在这套机制上。
- **共享订阅（Shared Subscription）** ：多个订阅者组成消费组（如 `$share/group1/topic`），同一条消息只投递给组内一人，天然实现负载均衡——这是 3.1.1 时代要绕很多弯才能做的事。
- **消息过期（Message Expiry Interval）** ：发布时给消息设有效期，过期的离线消息不再补发，避免设备上线时被一堆过时指令轰炸。
- **其他改进** ：主题别名（用短编号替代长主题名省流量）、Receive Maximum 流量控制、服务端主动断开通知、基于 Response Topic 的请求-响应模式支持等。

一句话总结：3.1.1 够用，5.0 好用，新项目建议直接上 5.0。

## 六、横向对比：MQTT vs HTTP vs CoAP vs WebSocket

光说 MQTT 好还不够，放到协议堆里比一比，定位就清晰了：

| 维度 | MQTT | HTTP | CoAP | WebSocket |
| --- | --- | --- | --- | --- |
| 通信模型 | 发布/订阅 | 请求/响应 | 请求/响应（类 REST） | 全双工数据流 |
| 传输层 | TCP | TCP | UDP | TCP |
| 最小报文开销 | 2 字节 | 头部数百字节 | 4 字节 | 帧头 2 字节起 |
| 云端主动推送 | 原生支持 | 不支持（需轮询改造） | 需配合 Observe | 支持 |
| 消息可靠性机制 | 内置三级 QoS | 依赖 TCP | 可选确认/重传 | 无，需自建 |
| 低功耗适配 | 优秀 | 较差 | 优秀（UDP 更省电） | 一般 |
| 典型适用场景 | 设备上云、遥测、远程控制 | 网页、开放 API、文件传输 | 资源极度受限的传感网 | 网页实时交互、聊天室 |

一句话定位： **HTTP 是给人用的，WebSocket 是给浏览器用的，CoAP 是给极限受限设备用的，MQTT 是给"海量设备 + 弱网 + 双向实时"场景用的。**

## 七、典型应用场景：你可能每天都在用

- **智能家居** ：MQTT 最大的基本盘。开源平台 Home Assistant 里大量设备通过 MQTT 接入；你家里的灯、插座、温湿度计，很可能此刻就在和某个 Broker 保持长连接。
- **工业物联网（IIoT）** ：产线上的 PLC、机床、仪表把数据上报到厂级 Broker，MES 系统和监控大屏按需订阅。阿里云 IoT、AWS IoT Core 等云平台，设备接入层的主协议都是 MQTT。
- **车联网** ：车队管理平台通过 MQTT 向成千上万台车下发指令、收集车况，QoS 分级正好匹配"位置上报可丢、远程锁车必须到"的差异化诉求。
- **环境与农业监测** ：田间地头的土壤传感器、水库边的水质监测站靠电池和太阳能运行，MQTT 的低功耗与断线缓存能力是刚需。

![](https://tc2.zeruns.com/tc/2026/07/23/image-2026072303341137071432743b128c6ec.png)

## 八、上手实践：十分钟跑通你的第一条 MQTT 消息

纸上得来终觉浅，动手的门槛其实非常低。

### 选 Broker

- **EMQX** ：国产开源，性能强悍、文档中文友好，还有在线公共测试 Broker `broker.emqx.io`，练手首选。
- **Mosquitto** ：Eclipse 基金会项目，C 语言编写，极轻量，树莓派上都能跑，适合本地调试。
- **HiveMQ** ：Java 系企业级方案，商业支持完善。

### 选客户端工具

- **MQTTX** ：EMQ 出品的跨平台桌面客户端（也有 CLI 和 Web 版），界面直观，调协议必备。
- **mqtt-cli / mosquitto\_pub、mosquitto\_sub** ：命令行党的趁手工具。

### 一段能跑的 Python 示例

安装依赖：`pip install paho-mqtt`

订阅端（subscriber.py）：

```python
import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, reason_code, properties):
    print("已连接:", reason_code)
    client.subscribe("home/livingroom/temperature", qos=1)

def on_message(client, userdata, msg):
    print(f"收到 [{msg.topic}] {msg.payload.decode()}")

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.emqx.io", 1883, 60)
client.loop_forever()

```

发布端（publisher.py）：

```python
import paho.mqtt.client as mqtt

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.connect("broker.emqx.io", 1883, 60)
client.publish("home/livingroom/temperature", "26.5", qos=1)
client.disconnect()
print("已发送")

```

先跑订阅端，再跑发布端，你就能在订阅端的终端里看到那条"26.5"——这就是物联网世界最小的一次"心跳"。

最后提醒一句：公共测试 Broker 是所有人共享的，千万别往上面发任何敏感数据；正式项目请自建或购买 Broker 服务，并务必开启 TLS 加密与账号鉴权。

## 九、总结

MQTT 的成功不在于它有多先进，而在于它 **极度克制** ：在"石油管道 + 卫星链路"这种苛刻环境里被倒逼出来的小报文、低功耗、弱网韧性，恰好命中了天量物联网设备的核心诉求。发布/订阅的解耦模型、三级 QoS 的灵活可靠性、遗嘱与保留消息这些围绕"设备会掉线"的务实设计，让它成了今天物联网事实上的标准协议。

如果你正在做智能硬件或后端开发，我的建议是：先用公共 Broker 和 MQTTX 把发布/订阅跑一遍，再认真读一遍 QoS 和会话机制——这两块吃透，MQTT 的八成就到手了。

三十年前那根横跨荒原的石油管道大概不会想到，为它设计的小协议，今天正跑在数十亿台设备上。技术的生命力，往往就藏在这种"刚刚好"的设计里。

### 延伸学习资源

- MQTT 官方规范（OASIS）：[https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html](https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html)
- MQTT 官网与入门教程：[https://mqtt.org/](https://mqtt.org/)
- HiveMQ MQTT Essentials 系列教程（英文，体系完整）：[https://www.hivemq.com/mqtt/](https://www.hivemq.com/mqtt/)
- 电子/嵌入式论坛：[https://bbs.eeclub.top/](https://bbs.eeclub.top/)

![](https://tc3.zeruns.com/tc/2026/07/23/image-2026072303360655457d6ca3b560f4ec4.png)

## 推荐阅读

- **高性价比和便宜的VPS/云服务器推荐:** [https://blog.zeruns.com/archives/383.html](https://blog.zeruns.com/archives/383.html)
- **各家AI大模型API平台推荐与简介：** [https://blog.zeruns.com/archives/947.html](https://blog.zeruns.com/archives/947.html)
- **我的世界服务器搭建教程：** [https://blog.zeruns.com/tag/mc/](https://blog.zeruns.com/tag/mc/)
- Hermes Agent 部署全指南，手把手教你搭建你的第一个AI助手：[https://blog.zeruns.com/archives/939.html](https://blog.zeruns.com/archives/939.html)
- 绿联（Ugreen）DXP4800Pro NAS 开箱评测与拆解：[https://blog.zeruns.com/archives/949.html](https://blog.zeruns.com/archives/949.html)
- 运算放大器（Op-Amp）入门指南：从原理到实战：[https://blog.zeruns.com/archives/938.html](https://blog.zeruns.com/archives/938.html)

English Version of the Article: [https://blog.zeruns.top/archives/96.html](https://blog.zeruns.top/archives/96.html)
