AI摘要

MQTT是物联网事实标准,基于发布/订阅模型,通过Broker解耦,报文仅2字节。支持QoS三级、遗嘱消息与保留消息,专为低功耗弱网设计。5.0版增加原因码、共享订阅等。较HTTP更省电、支持实时推送。

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

一、从一个智能大棚说起:为什么物联网不能只用 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.1MQTT 5.0(2019 年发布),5.0 是现在的推荐版本,后文会专门聊它。

eeClub-电子工程师社区:https://bbs.eeclub.top/

电子/单片机技术交流QQ群: 2169025065

三、核心架构:不是"打电话",而是"订报纸"

理解 MQTT,最关键的是理解它的通信模型——发布/订阅模式(Publish/Subscribe)

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

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

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

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

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

Topic:邮局里的"信箱编号"

消息靠什么分发?靠 Topic(主题)。Topic 是一个 UTF-8 字符串,用 / 分层,看起来像文件路径:

home/livingroom/temperature
home/livingroom/humidity
home/bedroom/temperature

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

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

四、关键特性逐个讲透

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 消息丢了"这类问题时,记得两端都查。

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"轻"的底气。

五、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 好还不够,放到协议堆里比一比,定位就清晰了:

维度MQTTHTTPCoAPWebSocket
通信模型发布/订阅请求/响应请求/响应(类 REST)全双工数据流
传输层TCPTCPUDPTCP
最小报文开销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 的低功耗与断线缓存能力是刚需。

八、上手实践:十分钟跑通你的第一条 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):

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):

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 的八成就到手了。

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

延伸学习资源

推荐阅读

最后修改:2026 年 07 月 23 日
如果您觉得我的文章有帮助,请随意赞赏,赞赏有助于激发博主的热情,感谢!