想象你住进了一个崭新的智慧小区:每个房间都有温度传感器,大门有智能门锁,走廊有烟雾报警器,楼顶有气象站。这些设备都想彼此沟通——温度超标了要通知空调,烟雾报警了要呼叫物业,门外有人按铃要告诉你的手机。如果让每台设备都直接联系其他设备,几百台设备互相拨号、占线、串线,乱成一团。于是小区里建起了一座中央邮局:Broker。所有设备只需把消息写成一封信投进邮局,邮局再按信封上的地址(主题)分拣派送;想收信的设备只要在邮局登记“我对哪些主题感兴趣”(订阅),邮局就会自动送信上门。MQTT,就是这套“物联网邮政服务”的行业标准协议。它诞生于 1999 年,专为低带宽、弱网络、海量设备的物联网场景设计:报文小到只有 2 字节、运行在稳定的 TCP 长连接上、天然支持一对多的发布订阅。本篇文章就带你走进这座邮局,看看消息是如何被投递、保障、托付与找回的。

岗位关联

掌握 MQTT 与 Broker,你就能为物联网设备搭建一条可靠、轻盈、可扩展的“消息邮路”,这是物联网与边缘智能方向从业者的基本功底。

目录
  1. 可视化演示
  2. MQTT协议概述:万物为何需要一座邮局
  3. 发布订阅模型:投递与订阅的契约
  4. Broker消息代理:邮局里的分拣车间
  5. QoS服务等级:三档投递保障
  6. 遗嘱与保留:离线通知与公告栏
  7. 主题通配符:邮路的模糊寻址
  8. Broker部署配置:开一家自己的邮局
  9. 可靠通信保障:心跳、重连与加密
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

演示MQTT轻量级消息协议:Broker发布订阅分发消息,讲解QoS级别、遗嘱消息与保留消息,构建可靠设备通信。

本节配有交互动效(进入视口后自动加载,约 3KB)。

发布订阅 发布 订阅 pub/sub Broker按主题分发消息

MQTT协议概述:万物为何需要一座邮局

在没有邮局的年代,小区里每台设备想通信,都得找到对方的“电话号码”直接拨过去。今天你装了一个新门锁,明天想让它和手机 App 对话,就得让门锁厂商、手机厂商、小区网关三方互相适配。设备一多,关系就成一团乱麻——这也是早期物联网项目最头疼的集成噩梦。MQTT 的诞生,就像是行业终于达成共识:与其让每台设备互相认识,不如建一座公共邮局,大家只跟邮局打交道。

这座“邮局”的学名叫 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输),由 IBM 在 1999 年为低带宽的卫星传感网络设计,如今已是 OASIS 国际标准。它跑在 TCP 长连接之上:设备开机后与 Broker 建立连接,之后一直复用这条链路收发消息,而不是像 HTTP 那样每次请求都重新握手。更重要的是,它把报文做得极其精简。

回到小区比喻:邮局从来不会让住户为了寄一封信重新装修一栋楼。MQTT 的“轻”,正是为了在农田、井盖、车底这些带宽捉襟见肘的地方,让设备依然说得上话。

最小报文开销MQTT=2 字节≪HTTP 请求头≥200 字节\text{最小报文开销}_{\text{MQTT}} = 2\ \text{字节} \ll \text{HTTP 请求头} \geq 200\ \text{字节}
MQTT 的报文头只有 2 字节,而 HTTP 光请求头就要几百字节——对电池供电的传感器来说,省下的每一字节都是真金白银的续航。
  1. 固定报文头MQTT 控制报文最简时,固定头只占 2 字节——首字节存放报文类型与标志,次字节存放剩余长度。
    固定头=报文类型+标志⏟1 字节+剩余长度⏟1 字节\text{固定头} = \underbrace{\text{报文类型+标志}}_{1\,\text{字节}} + \underbrace{\text{剩余长度}}_{1\,\text{字节}}
  2. HTTP 头的开销一次 HTTP 请求至少携带请求行、Host 与各类头字段,几百字节起步。
    HTTP 请求头≥200 字节\text{HTTP 请求头} \geq 200\,\text{字节}
  3. 对比结论两套开销相差百倍,同一条窄带通道里 MQTT 能传递的消息数量远高于 HTTP。
    HTTP 头MQTT 最小头≥100\frac{\text{HTTP 头}}{\text{MQTT 最小头}} \geq 100

发布订阅模型:投递与订阅的契约

邮局运行的第一条规则是:寄信人不必知道收信人是谁。你往邮筒里投一封信,邮局只看信封上的地址(主题),按地址分拣,从不追问“你和收信人是什么关系”。反过来,收信人只要在邮局登记了自己感兴趣的栏目,邮局就会风雨无阻地送上门。发布订阅(Pub/Sub)模式,就是把这套契约翻译成了协议。

具体到 MQTT 里,角色被拆成三个:发布者(Publisher)把消息和主题交给 Broker 便转身离开;订阅者(Subscriber)告诉 Broker “我对哪些主题感兴趣”;Broker 负责按主题把消息投递给所有匹配的订阅者。三方互不感知对方的存在——门锁厂商不需要知道手机 App 是谁写的,新设备接入时也不需要改动任何老设备。

这份“契约”最大的价值是解耦:发送方与接收方在时间上解耦(不必同时在线)、空间上解耦(互不知道对方地址)、节奏上解耦(一方忙时另一方不必等待)。就像你投完信就可以去忙别的,邮差什么时候送、送给谁,都不需要你操心。

Broker 路由: (t,m)↦{s∈S∣t∈subscribed(s)}\text{Broker 路由}:\ (t, m) \mapsto \{ s \in S \mid t \in \text{subscribed}(s) \}
一次发布动作,Broker 把主题 t 和消息 m 路由给订阅列表里包含 t 的所有订阅者——这就是一对多广播的全部秘密。
  1. 发布元组发布者把主题 t 与消息 m 一并交给 Broker,Broker 不关心发布者是谁。
    (t,m) 表示一次发布(t, m)\ \text{表示一次发布}
  2. 订阅者集合系统中有订阅者集合 S,每个订阅者维护着自己感兴趣的订阅列表。
    S={s1,s2,… }S = \{s_1, s_2, \dots\}
  3. 集合筛选Broker 遍历 S,只要某个订阅者的订阅列表包含 t,就把消息投进它的信箱。
    s∈S∧t∈subscribed(s)s \in S \land t \in \text{subscribed}(s)

Broker消息代理:邮局里的分拣车间

邮局最核心的资产不是邮筒,而是后院那间分拣车间。所有信件汇聚到这里,按地址归类、按片区装车、再交给不同的邮差。MQTT 的 Broker 就是这间分拣车间:它维护着所有设备的连接状态,接收发布者投来的消息,根据主题匹配订阅者,再逐条转发出去。没有 Broker,设备之间就要两两直连,连接数会随设备数量爆炸式增长。

除了路由,Broker 还承担连接管理与会话状态维护:记录每个客户端的订阅列表、未确认的 QoS1/QoS2 消息、离线期间需要补发的消息。它是整个邮路的“总调度”,也是故障排查时首先要盯住的枢纽。

C直连=N(N−1)2≫CBroker=N\displaystyle C_{\text{直连}} = \frac{N(N-1)}{2} \gg C_{\text{Broker}} = N
直连模式下连接数随设备数平方增长,而经过 Broker 只需要线性增长——这正是海量物联网设备选择星型拓扑的根本原因。
  1. 两两直连数N 台设备如果两两互联,需要的连接数是组合数 C(N,2)。
    N(N−1)2\frac{N(N-1)}{2}
  2. 星型连接数全部设备只连 Broker,每台仅 1 条链路。
    N×1=NN \times 1 = N
  3. 规模对比当 N=100 时,直连需要 4950 条,经 Broker 只需 100 条。
    4950≫1004950 \gg 100

QoS服务等级:三档投递保障

寄信时你可以选不同的服务档次:贴普通邮票的平信,寄丢了没人负责;挂号信要求收件人签字确认,但可能因为重复投递让你收到两封一模一样的;还有一种是快递员当面验货、双方签字、回执归档,保证货物不多不少刚好送一次。MQTT 的 QoS(Quality of Service,服务质量)也是同样的三档套餐。

选哪一档,取决于消息值多少钱。室内温度偶尔丢一条,下一条马上补上,用 QoS0 就够;门锁开锁指令必须送达,用 QoS1;而涉及计费、防重入的指令,才值得付出四段握手的代价上 QoS2。邮局的聪明之处,是把选择权交给寄信人。

QoS0:PUBLISH;QoS1:PUBLISH→PUBACK;QoS2:PUBLISH→PUBREC→PUBREL→PUBCOMP\text{QoS0}: \text{PUBLISH};\quad \text{QoS1}: \text{PUBLISH} \to \text{PUBACK};\quad \text{QoS2}: \text{PUBLISH} \to \text{PUBREC} \to \text{PUBREL} \to \text{PUBCOMP}
QoS0 只有一条发送报文;QoS1 加一条确认;QoS2 则要经过四段握手——可靠性越高,网络往返次数越多。
  1. QoS0 单程发送只发一条 PUBLISH,发完即忘,不设任何确认,消息可能丢失。
    QoS0: PUBLISH\text{QoS0}:\ \text{PUBLISH}
  2. QoS1 一次确认接收方回 PUBACK;发送方收不到确认会重发,因此存在重复风险。
    QoS1: PUBLISH→PUBACK\text{QoS1}:\ \text{PUBLISH} \to \text{PUBACK}
  3. QoS2 四段握手接收方先回 PUBREC,发送方回 PUBREL 释放,最后 PUBCOMP 完成,确保恰好一次。
    QoS2: PUBLISH→PUBREC→PUBREL→PUBCOMP\text{QoS2}:\ \text{PUBLISH} \to \text{PUBREC} \to \text{PUBREL} \to \text{PUBCOMP}
  4. 语义归纳三档分别对应“最多一次、至少一次、恰好一次”。

遗嘱与保留:离线通知与公告栏

有位探险家每次进山前都会在邮局留下一封装好、写清收件人的信,并叮嘱:“如果到了约定时间我没回来,就把这封信寄出去。”这就是遗嘱消息(Will Message)。MQTT 设备在建立连接时,可以预先在 Broker 上登记一封信和触发条件:一旦连接异常中断——比如断电、断网、崩溃——Broker 就代替这台“失联”的设备把信寄出。注意,遗嘱是 Broker 代发的,设备正常下线时主动发送 DISCONNECT,Broker 会撕掉这封信,不会寄出。

邮局门口还有一块公告栏:最新的停水通知、最新的电价表,永远贴在最上面。这就是保留消息(Retained Message)。发布者可以在发布时打上"retain"标记,Broker 会为这个主题保存最后一条消息。任何新订阅者一注册,立刻收到这块公告栏上的内容,而不必苦等下一次发布。

没有遗嘱,平台可能要等好几分钟才发现某个传感器“失联”;没有保留消息,你刚打开的 App 屏幕上会是一片空白。这两项机制,一个管“死的通知”,一个管“活的快照”,是物联网系统里感知离线与同步状态的左右手。

遗嘱: 异常断开⇒Broker 代发;保留: 新订阅⇒立即回放最后一条\text{遗嘱}:\ \text{异常断开} \Rightarrow \text{Broker 代发};\qquad \text{保留}:\ \text{新订阅} \Rightarrow \text{立即回放最后一条}
遗嘱消息让系统在设备“猝死”时第一时间知晓;保留消息让新加入的订阅者立刻拿到该主题的最新状态。
  1. 异常触发心跳超时、网络崩溃、设备断电都被视为异常断开,此时 Broker 才代发遗嘱。
    异常断开⇒Broker 代发遗嘱\text{异常断开} \Rightarrow \text{Broker 代发遗嘱}
  2. 正常离场设备主动发 DISCONNECT 优雅退出,Broker 丢弃遗嘱不代发。
    DISCONNECT⇒遗嘱作废\text{DISCONNECT} \Rightarrow \text{遗嘱作废}
  3. 保留回放新订阅者注册后,Broker 立即把该主题最新一条保留消息推送给它。
    新订阅⇒立即回放最后一条\text{新订阅} \Rightarrow \text{立即回放最后一条}
  4. 状态快照保留消息是每个主题的“最新状态公告栏”,不是历史档案仓库。

主题通配符:邮路的模糊寻址

邮局分拣信件时,地址是有层级的:先看小区,再看楼栋,再看房间。MQTT 的主题也长这样,用斜杠分隔层级,比如 home/living/temperature 表示“家/客厅/温度”。但有时你不想精确到某一间房,而是想订阅整栋楼的所有温度数据——这时就需要通配符。

MQTT 只有两个通配符:加号 + 匹配一个层级,井号 # 匹配剩余的所有层级(包括零层)。它们让订阅者可以用一个模式覆盖一批主题,就像订报纸时勾选“整栋楼的住户名单”而不是一个个抄名字。

通配符是把双刃剑:用得好,一条订阅覆盖一片设备;用得滥,订阅者会收到大量无关消息。邮局分拣员最喜欢的,永远是地址写得又规范又有层次的住户。

home/+/temperature⇒{home/kitchen/temperature, home/bedroom/temperature}\text{home}/+/temperature \Rightarrow \{\text{home/kitchen/temperature},\ \text{home/bedroom/temperature}\}
一个带 + 的订阅模式,可以同时接收客厅和卧室的温度数据——加号是“这一层任意房间”的意思。
  1. 层级分隔斜杠 / 把主题分成层级,像“小区/楼栋/房间/属性”。
    home/living/temperature\text{home}/\text{living}/\text{temperature}
  2. 单层通配 ++ 恰好匹配一个层级,home/+/temperature 匹配任意房间的温度。
    home/+/temperature→home/kitchen/temperature\text{home}/+/\text{temperature} \to \text{home}/\text{kitchen}/\text{temperature}
  3. 多层通配 ## 匹配剩余全部层级,home/# 匹配 home 下所有事件。
    home/#→home/living/temperature, home/bedroom/humidity\text{home}/\# \to \text{home}/\text{living}/\text{temperature},\ \text{home}/\text{bedroom}/\text{humidity}
  4. 边界规则通配符只能占满整个层级,不能写成 tem+ 这种残缺形式。

Broker部署配置:开一家自己的邮局

要享受邮局的便利,你得先有一家邮局。开源社区最常用的 MQTT Broker 是 Mosquitto——它轻量、跨平台、一条命令就能启动。部署它就像选定邮局选址:要决定开在哪个端口等人来寄信(监听端口)、要不要检查来者身份(认证授权)、信件要不要存档(持久化)。

默认情况下,Mosquitto 在 1883 端口提供明文 MQTT 服务,在 8883 端口提供 TLS 加密服务。生产环境绝不能裸奔:要关闭匿名接入,用 password_file 指定账号口令文件,只放行登记过的设备。配置写在 mosquitto.conf 里,寥寥几行就能把“开放式邮筒”变成“持证入场”的社区邮局。

部署完成后,还要根据设备量调整 max_connections、开启持久化等参数。邮局开得好不好,决定了整条邮路是畅通无阻还是积压成山。

listener 1883+password_file⇒仅认证设备可接入\text{listener}\ 1883 + \text{password\_file} \Rightarrow \text{仅认证设备可接入}
一行 listener 声明服务端口,一行 password_file 引入口令校验,再关掉匿名开关,邮局就从“人人可投”变成“凭证入场”。
  1. 监听端口listener 1883 声明 Broker 在 1883 端口等待设备接入。
    listener 1883\text{listener}\ 1883
  2. 匿名开关allow_anonymous false 关闭匿名连接,杜绝未登记设备进场。
    allow_anonymous=false\text{allow\_anonymous} = \text{false}
  3. 口令文件password_file 指向密码文件,设备凭账号口令完成身份校验。
    password_file→账号校验\text{password\_file} \to \text{账号校验}
  4. 隔离效果三重配置叠加后,只有登记过的设备才能连接邮局。

可靠通信保障:心跳、重连与加密

邮局和住户之间怎么确认对方还活着?答案是约定暗号:每隔一段时间,住户敲一下门,邮局回敲一下。MQTT 里这叫心跳(KeepAlive):设备在连接时和 Broker 约定一个时间间隔,双方定期互发 PINGREQ / PINGRESP 报文。只要还收得到对方的报文,连接就健康。

如果超过约定时间还没动静呢?Broker 不会立刻翻脸,而是给一点宽限——按标准,超过 1.5 倍 KeepAlive 时间仍未收到任何报文,才判定这条连接死亡。这个“宽限期”好比敲门后多等半分钟,防止网络抖动造成误判。

再加上 TLS 加密传输,设备与 Broker 之间的信路就既有心跳保活、又有断线重连、还有全程加密。邮局想长久运营,靠的就是这套“永远在线、掉线能拉回来、内容不泄密”的可靠性工程。

T判定离线=1.5×Tkeepalive\displaystyle T_{\text{判定离线}} = 1.5 \times T_{\text{keepalive}}
心跳周期是 T,超过 1.5 倍 T 仍无任何报文才判定离线——宽限容忍抖动,严格避免误杀。
  1. 心跳周期设备与 Broker 约定每隔 T_keepalive 秒互发 PINGREQ/PINGRESP。
    Tkeepalive=60 sT_{\text{keepalive}} = 60\ \text{s}
  2. 超时容忍Broker 给出 1.5 倍宽限,容忍网络抖动造成的短暂沉默。
    1.5×Tkeepalive1.5 \times T_{\text{keepalive}}
  3. 离线判定超过 1.5 倍仍无任何报文,Broker 判定连接死亡,触发遗嘱等善后动作。
    T判定离线=90 sT_{\text{判定离线}} = 90\ \text{s}
  4. 重连补位设备侧检测到超时后自动发起重连,并配合会话恢复完成消息续传。

AI 应用场景

智慧小区环境监控

阶段:数据采集与传输层

解决的问题:传统方案里传感器直连平台,设备一多连接就乱,数据上报靠定时轮询,时效差、功耗高。MQTT 加 Broker 让传感器只负责发布,平台按主题订阅,天然解耦且支持实时推送。

具体案例:某智慧小区部署 200 个温湿度与空气质量传感器。传感器以 QoS0/QoS1 发布到 estate/block/room/env 主题,物业大屏与 AI 分析平台分别订阅汇总;当某个传感器断电失联时,Broker 代发遗嘱消息 estate/block/room/offline,运维系统自动生成检修工单。新装的大屏设备通过保留消息立即拿到各房间最新环境数据,无需等待下一轮上报。

工业设备预测性维护

阶段:边缘数据接入与特征传输

解决的问题:工厂内网抖动频繁,关键振动数据一旦丢失就会影响故障诊断模型输入。QoS1 保证数据至少到达一次,配合遗嘱消息让云端第一时间感知设备“猝死”。

具体案例:某工厂为 50 台电机加装振动传感器,边缘网关以 QoS1 发布到 factory/line/motor/vibration,云端 AI 模型订阅后做异常检测;模型发现异常特征后,通过控制主题下发停机指令。某台电机突然断电,Broker 立即代发遗嘱 factory/line/motor/offline,应急系统在 5 秒内触发报警,维修人员提前到场。

车联网轨迹追踪

阶段:实时轨迹数据汇聚

解决的问题:车辆频繁进出隧道导致信号中断,调度中心难以掌握最新位置。MQTT 的保留消息让每一辆车的“最后已知位置”始终挂在 Broker 上,新客户端上线即可秒级恢复全貌。

具体案例:某出租车公司每辆车每 5 秒上报一次 GPS,发布到保留主题 fleet/car/<id>/location。新调度员登录系统时,订阅全部车辆位置主题,立即收到每辆车的最新坐标,而不是等待下一次上报周期;车辆驶出无信号隧道后自动重连并续传,轨迹在云端 AI 平台拼接成完整路线。

Python 演示

python65 行
import re  class MiniBroker:    """一个极简的消息代理(邮局)"""     def __init__(self):        self.subscriptions = []  # 形如 (client, pattern) 的订阅列表        self.retained = {}       # 保留消息: {topic: payload}     def subscribe(self, client, pattern):        self.subscriptions.append((client, pattern))     def publish(self, topic, payload, qos=0, retain=False):        if retain:            self.retained[topic] = payload        targets = []        for client, pattern in self.subscriptions:            if self._match(pattern, topic):                client.receive(topic, payload, qos)                targets.append(client.name)        return targets     def _match(self, pattern, topic):        regex = '^' + pattern.replace('+', '[^/]+').replace('#', '.*') + '$'        return re.match(regex, topic) is not None  class Device:    """一个 IoT 设备(可发布也可订阅)"""     def __init__(self, name, broker):        self.name = name        self.broker = broker        self.received = []     def publish(self, topic, payload, qos=0, retain=False):        self.broker.publish(topic, payload, qos, retain)     def subscribe(self, pattern):        self.broker.subscribe(self, pattern)     def receive(self, topic, payload, qos):        self.received.append((topic, payload, qos))        print('[{}] 收到 {}: {} (QoS{})'.format(self.name, topic, payload, qos))  def main():    broker = MiniBroker()    sensor = Device('卧室温度传感器', broker)    phone = Device('手机App', broker)    speaker = Device('语音助手', broker)     phone.subscribe('home/+/temperature')    speaker.subscribe('home/+/temperature')     sensor.publish('home/bedroom/temperature', '24.5', qos=1, retain=True)    broker.publish('home/living/temperature', '26.0', qos=0, retain=True)     for topic, payload in broker.retained.items():        print('保留消息: {} = {}'.format(topic, payload))  if __name__ == '__main__':    main()
目的:在没有任何外部依赖的情况下,演示 MQTT 的发布订阅路由、通配符匹配、QoS 标记传递与保留消息存储,帮助理解 Broker 的内部视角。
  1. class MiniBroker:邮局本体:一张订阅登记表加一张保留消息公告栏。
  2. regex = '^' + pattern.replace('+', '[^/]+').replace('#', '.*') + '$'把 MQTT 通配符翻译成正则,实现 + 匹配单层、# 匹配多层的分拣逻辑。
  3. if self._match(pattern, topic): client.receive(...)Broker 命中订阅后把消息投递给设备,设备端回调即“收信”。
  4. if retain: self.retained[topic] = payload打上 retain 标记的消息会被挂上公告栏,供新订阅者回放。
  5. sensor.publish('home/bedroom/temperature', '24.5', qos=1, retain=True)设备以 QoS1 发布并保留消息,两个订阅者因通配符模式同时收到。

常见误区

误区我觉得 MQTT 和 HTTP 差不多,每次发消息都要先建立连接、发完再断开,所以效率高不了多少。

正解MQTT 基于 TCP 长连接,设备与 Broker 握手一次后连接持续复用,之后的所有发布订阅都在这条链路上以极小的消息帧传输。就像和邮局签了长期投递协议,而不是每次寄信都重新签合同。只有连接断开重连时才需要再次握手。

为何常见:HTTP 是典型的请求-响应且默认无状态,习惯了 HTTP 的人容易把“每次通信都要建连”的心智模型套到 MQTT 上。

误区QoS 等级越高越“高级”,那我所有消息都用 QoS2,既快又稳,一劳永逸。

正解QoS2 需要四段握手,网络往返次数最多、延迟和带宽开销最大;QoS0 只有一次发送,最快但可能丢。选档要看业务:温度偶尔丢一条无伤大雅用 QoS0;门锁指令要确保到达用 QoS1;计费、防重入场景才用 QoS2。

为何常见:直觉上“更可靠 = 更好”,忽略了可靠性背后是用更多的网络往返换来的,成本和收益需要权衡。

误区保留消息就是把所有消息都存在 Broker 上,新设备接入后随时可以查历史记录。

正解保留消息每个主题只保存最新一条。它是一块公告栏,不是档案馆。如果需要完整历史,要靠时序数据库落盘或专门的持久化方案,MQTT 本身不负责历史归档。

为何常见:“保留”一词容易被理解成“持久化存储”,而它的设计目标其实是状态同步——让后来者立刻拿到最新快照。

误区设备要下线了,主动发一条遗嘱消息告诉别人“我走了”,就完成了告别。

正解遗嘱消息在连接建立时就预先登记在 Broker 上,只有连接异常中断(断网、断电、崩溃、心跳超时)时 Broker 才代发。设备正常下线时应发送 DISCONNECT,Broker 会删除遗嘱而不代发——正常告别不需要邮局替你寄遗书。

为何常见:“遗嘱”的日常语义是主动立嘱,容易忽略 MQTT 里真正的代发者是 Broker 这个“受托人”,而设备只是预先寄存。

面试题

Q1. MQTT 协议默认运行在哪种传输协议之上?

单选题 · easy

  • A.基于UDP的数据报协议
  • B.基于TCP的字节流协议← 正确答案
  • C.基于HTTP的请求响应模式
  • D.基于ICMP的探测回显

答案:B。MQTT 基于 TCP 长连接,设备与 Broker 建连后持续复用链路;UDP、HTTP、ICMP 都不是 MQTT 的传输基础。就像邮局的长期投递协议依赖稳定的运输网络,TCP 就是这个运输网络。

Q2. MQTT 体系中负责消息接收、路由与转发的是?

单选题 · easy

  • A.发布者客户端设备
  • B.订阅者客户端设备
  • C.Broker消息代理服务← 正确答案
  • D.主题Topic结构对象

答案:C。Broker 是中央邮局,负责接收发布者消息、按主题匹配订阅者并转发;发布者只投递,订阅者只登记,主题只是消息的“地址”而非转发主体。

Q3. QoS等级为0时,消息投递的语义是什么?

单选题 · easy

  • A.最多一次,发送后可能丢失← 正确答案
  • B.至少一次,确认前可能重复
  • C.恰好一次,靠握手保证不重复
  • D.断线重连后由Broker自动补发

答案:A。QoS0 只发送一条 PUBLISH 且不确认,属于“平信”,可能丢失但最快;QoS1 是“挂号信”,至少一次但可能重复;QoS2 是四段握手的“签收保价”,恰好一次。

Q4. 遗嘱消息在连接异常中断时由谁代发?

单选题 · mid

  • A.设备自身主动发出遗嘱
  • B.Broker按预先登记代发← 正确答案
  • C.订阅者收到心跳超时通知
  • D.边缘网关转发离线事件

答案:B。遗嘱在 CONNECT 时预先登记在 Broker 上,连接异常断开时由 Broker 代为发出;设备正常下线发 DISCONNECT 则遗嘱作废。它的本质是“受托人执行的遗书”,而非设备自己寄出的信。

Q5. 保留消息(Retained Message)的核心作用是?

单选题 · mid

  • A.备份该主题的全部历史消息
  • B.为新订阅者保留最新一条消息← 正确答案
  • C.提高消息在公网的传输速度
  • D.自动把消息转为离线缓存队列

答案:B。保留消息每个主题只存最新一条,新订阅者注册后立即收到这条“公告栏”内容,用于状态同步;它既不存历史,也不负责加速,更不等同于离线队列。

Q6. 主题模式"home/+/temp"能匹配哪个真实主题?

单选题 · hard

  • A.主题home/temp只有两层段
  • B.主题home/kitchen/temp三层段← 正确答案
  • C.主题home/kitchen/floor三层段
  • D.主题kitchen/home/temp三层段

答案:B。+ 恰好匹配一个层级,模式 home/+/temp 要求三段且首段为 home、末段为 temp。A 只有两段,C 末段不是 temp,D 首段不是 home,只有 B 完全命中。

Q7. 相比HTTP轮询,MQTT有哪些典型优势?

多选题 · mid

  • A.报文开销更小适合低带宽场景← 正确答案
  • B.服务器可主动推送消息给设备← 正确答案
  • C.天然支持一对多的发布订阅← 正确答案
  • D.QoS3可确保消息百分之百到达

答案:ABC。MQTT 报文头最小仅 2 字节、基于长连接可实时推送、发布订阅天然支持一对多。但 MQTT 只有 QoS0/1/2 三档,不存在 QoS3,D 错误。

Q8. 关于MQTT的可靠投递机制,以下说法正确的是?

多选题 · extreme

  • A.QoS1基础ACK丢失会触发发送方重传← 正确答案
  • B.QoS2通过四段握手实现精确一次投递← 正确答案
  • C.DUP标志与报文ID用于识别重复消息← 正确答案
  • D.QoS0投递失败时Broker会持久化重发

答案:ABC。QoS1 发送方收不到 PUBACK 会重传,QoS2 用 PUBLISH→PUBREC→PUBREL→PUBCOMP 保证恰好一次,DUP 标志与报文 ID 配合可识别重复。QoS0 不确认也不重传,Broker 不会为它持久化重发,D 错误。

Q9. Broker是如何判定设备已离线的?

单选题 · mid

  • A.超过1.5倍KeepAlive未收到任何报文← 正确答案
  • B.恰好达到KeepAlive时长便立刻断链
  • C.接收报文数量低于平日平均阈值即断
  • D.设备收到PINGRESP后未回复即判定

答案:A。Broker 按标准给出 1.5 倍 KeepAlive 的宽限期,超过后仍无任何报文才判定离线。立即断链会误杀网络抖动中的设备;报文数量阈值、对 PINGRESP 的回复都不是标准判定依据。

Q10. MQTT主题通配符的使用规则,正确的是?

多选题 · easy

  • A.加号匹配某个层级中的任意名称← 正确答案
  • B.井号匹配多个层级也可匹配零层← 正确答案
  • C.问号匹配任意单个字符补全层级
  • D.星号匹配所有层级直至主题结束

答案:AB。+ 匹配一个层级,# 匹配剩余零到多个层级,这是 MQTT 仅有的两个通配符。? 和 * 都不是 MQTT 规范中的通配符,C、D 错误。