MQTT协议详解笔记
一、MQTT概述
1.1 什么是MQTT
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种基于发布/订阅模式的轻量级通讯协议,构建于TCP/IP协议之上。
1.2 主要特点
-
轻量级:协议开销小,头部最小2字节
-
低带宽:适合网络条件差的场景
-
简单开放:易于实现和部署
-
可靠传输:支持三种服务质量等级
1.3 应用场景
-
物联网(IoT):传感器数据采集
-
移动应用:推送消息
-
M2M通信:设备间通信
-
受限环境:低功耗、低带宽设备
1.4 协议版本
-
MQTT 3.1.1:当前标准版本(2014年发布)
-
MQTT-SN:针对非TCP/IP网络的简化版
二、MQTT核心概念
2.1 三种角色
| 角色 | 描述 | 功能 |
|---|---|---|
| 发布者(Publisher) | 发送消息的客户端 | 发布消息到特定主题 |
| 代理(Broker/Server) | 消息中转服务器 | 接收、存储、转发消息 |
| 订阅者(Subscriber) | 接收消息的客户端 | 订阅感兴趣的主题 |
2.2 消息结构
┌─────────────────────────────────┐
│ 固定头(Fixed Header) │ ← 必选,2字节最小
├─────────────────────────────────┤
│ 可变头(Variable Header) │ ← 可选,因报文类型而异
├─────────────────────────────────┤
│ 有效载荷(Payload) │ ← 可选,消息内容
└─────────────────────────────────┘
2.3 关键术语
| 术语 | 描述 | 备注 |
|---|---|---|
| 会话(Session) | 客户端和服务端之间的状态交互 | 可跨越多个网络连接 |
| 客户端标识(ClientID) | 客户端的唯一标识符 | 1-23字符,只能包含字母数字 |
| 主题(Topic) | 消息的标签/分类 | UTF-8字符串,区分大小写 |
| 主题过滤器(Topic Filter) | 订阅时使用的表达式 | 支持通配符 |
| 负载(Payload) | 消息的实际内容 | 最大256MB |
三、MQTT报文类型(14种)
3.1 连接相关
| 报文类型 | 值 | 方向 | 描述 |
|---|---|---|---|
| CONNECT | 1 | 客户端→服务端 | 建立连接 |
| CONNACK | 2 | 服务端→客户端 | 连接确认 |
3.2 发布/订阅相关
| 报文类型 | 值 | 方向 | 描述 |
|---|---|---|---|
| PUBLISH | 3 | 双向 | 发布消息 |
| PUBACK | 4 | 双向 | QoS 1发布确认 |
| PUBREC | 5 | 双向 | QoS 2第一步确认 |
| PUBREL | 6 | 双向 | QoS 2第二步确认 |
| PUBCOMP | 7 | 双向 | QoS 2第三步确认 |
| SUBSCRIBE | 8 | 客户端→服务端 | 订阅请求 |
| SUBACK | 9 | 服务端→客户端 | 订阅确认 |
| UNSUBSCRIBE | 10 | 客户端→服务端 | 取消订阅 |
| UNSUBACK | 11 | 服务端→客户端 | 取消订阅确认 |
3.3 连接维护
| 报文类型 | 值 | 方向 | 描述 |
|---|---|---|---|
| PINGREQ | 12 | 客户端→服务端 | 心跳请求 |
| PINGRESP | 13 | 服务端→客户端 | 心跳响应 |
| DISCONNECT | 14 | 客户端→服务端 | 断开连接 |
四、服务质量(QoS)等级
4.1 QoS 0:最多一次(At Most Once)

-
特点:不确认,可能丢失
-
应用场景:环境传感器数据,丢失不影响
-
传输次数:0或1次
4.2 QoS 1:至少一次(At Least Once)

-
特点:确认机制,可能重复
-
存储要求:发送者需持久化
-
应用场景:重要但不严格要求唯一的数据
4.3 QoS 2:恰好一次(Exactly Once)

-
特点:四步握手,确保唯一
-
存储要求:双方都需持久化
-
应用场景:计费系统,支付等关键业务
五、会话管理与连接控制
5.1 CleanSession标志
| 值 | 含义 | 会话状态 |
|---|---|---|
| 0 | 恢复会话 | 保留会话状态,重连后恢复 |
| 1 | 清理会话 | 新建会话,不保留状态 |
5.2 会话状态内容
客户端会话状态
-
已发送未确认的QoS 1/2消息
-
已接收未确认的QoS 2消息
服务端会话状态
-
会话存在标志
-
客户端订阅信息
-
已发送未确认的QoS 1/2消息
-
待发送的QoS 1/2消息
-
已接收未确认的QoS 2消息
-
(可选)待发送的QoS 0消息
5.3 遗嘱机制(Last Will & Testament)
// CONNECT报文中的遗嘱相关字段
Will Flag = 1; // 启用遗嘱
Will QoS = 0/1/2; // 遗嘱消息QoS
Will Retain = 0/1; // 是否保留遗嘱消息
Will Topic = "topic"; // 遗嘱主题
Will Message = "msg"; // 遗嘱消息内容
触发条件:
-
网络I/O错误或故障
-
Keep Alive超时
-
客户端非正常断开
-
协议错误导致连接关闭
5.4 心跳机制(Keep Alive)
-
作用:维持长连接,检测对方存活
-
超时:服务端在1.5×KeepAlive时间内未收到报文则断开
-
范围:0-65535秒(0表示关闭)
-
最大值:18小时12分15秒
六、主题与订阅机制
6.1 主题命名规则
| 规则 | 说明 |
|---|---|
| 字符集 | UTF-8编码,不能包含空字符 |
| 长度 | 最长65535字节 |
| 层级 | 使用"/"分隔,支持任意层级 |
| 区分大小写 | "A"和"a"是不同的主题 |
| 允许空格 | 可以包含空格字符 |
6.2 通配符
6.2.1 单层通配符(+)
有效:
sport/tennis/+ 匹配 sport/tennis/player1, sport/tennis/player2
+/tennis/player1 匹配 any/tennis/player1
+ 匹配单层级主题
无效:
sport+ 通配符必须占据整个层级
6.2.2 多层通配符(#)
有效:
sport/tennis/# 匹配 sport/tennis, sport/tennis/player1, sport/tennis/player1/score
sport/# 匹配 sport 及所有子层级
# 匹配所有主题(应谨慎使用)
无效:
sport/tennis# 通配符前必须有"/"
sport/#/ranking 通配符必须是最后字符
6.2.3 特殊主题($开头)
规则:
- $开头的主题不能匹配通配符(#或+)开头的过滤器
- 订阅"#"不会收到$开头的消息
- 订阅"$SYS/#"可接收系统主题
- $SYS/ 通常用于服务器监控和管理
6.3 订阅与QoS降级
// SUBSCRIBE报文结构
主题过滤器1 + QoS请求1
主题过滤器2 + QoS请求2
...
主题过滤器N + QoS请求N
// SUBACK返回码
0x00 - 最大QoS 0授予成功
0x01 - 最大QoS 1授予成功
0x02 - 最大QoS 2授予成功
0x80 - 订阅失败
QoS降级规则:
-
服务端可能授予比请求低的QoS等级
-
实际消息QoS = min(发布QoS, 授予QoS)
-
高QoS消息降级后可能重复
七、报文标识与重传机制
7.1 报文标识符(Packet Identifier)
| 报文类型 | 是否需要Packet ID | 说明 |
|---|---|---|
| PUBLISH (QoS>0) | 是 | 非零16位整数 |
| PUBACK/PUBREC | 是 | 与对应PUBLISH相同 |
| PUBREL/PUBCOMP | 是 | 与对应PUBLISH相同 |
| SUBSCRIBE/SUBACK | 是 | 匹配对应请求 |
| UNSUBSCRIBE/UNSUBACK | 是 | 匹配对应请求 |
7.2 重传规则
-
重传条件:在相同Session内等待确认超时
-
DUP标志:重传时设置为1
-
Packet ID重用:确认完成后可重用
-
顺序保证:必须按原始顺序重传
7.3 消息排序
QoS 1可能顺序:1, 2, 3, 2, 3, 4 # 可能重复导致乱序
QoS 2保证顺序:1, 2, 3, 4 # 严格保证有序无重复
控制措施:
- 设置传输窗口(in-flight window)=1可避免QoS 1乱序
- QoS 2天然保证有序
八、保留消息(Retain)
8.1 Retain标志作用
| Retain值 | 服务端行为 | 订阅者影响 |
|---|---|---|
| 0 | 不存储,不替换现有保留消息 | 仅当前订阅者收到 |
| 1 | 存储消息和QoS,替换旧消息 | 新订阅者立即收到 |
8.2 保留消息特性
-
单主题单消息:每个主题最多一个保留消息
-
零字节清理:发送零字节保留消息可清除
-
存储限制:服务端内存紧张时可丢弃
-
遗嘱保留:Will Retain标志同理
九、安全机制
9.1 传输层安全
| 端口 | 协议 | 加密 | 说明 |
|---|---|---|---|
| 1883 | TCP | 无 | 标准MQTT端口 |
| 8883 | TLS | 是 | 推荐生产环境使用 |
| 8080 | WebSocket | 无 | WebSocket连接 |
| 8081 | WebSocket+TLS | 是 | 安全WebSocket |
9.2 认证方式
9.2.1 用户名/密码认证
// CONNECT报文中的认证字段
UserName Flag = 1; // 启用用户名
Password Flag = 1; // 启用密码
UserName = "user"; // UTF-8字符串
Password = "pass"; // 二进制数据
9.2.2 其他认证方式
-
TLS客户端证书:双向认证
-
外部系统:LDAP、OAuth、操作系统认证
-
应用层认证:通过消息传递凭证
9.3 安全风险与防护
| 风险类型 | 防护措施 |
|---|---|
| 中间人攻击 | TLS加密,VPN隧道 |
| 重放攻击 | 时间戳,序列号,TLS |
| 拒绝服务 | 频率限制,黑名单 |
| 数据泄露 | 静态数据加密 |
| 身份伪造 | 强身份验证 |
9.4 异常行为检测
监控指标:
- 频繁连接/认证请求
- 异常断开连接
- 主题扫描行为
- 发送无订阅者消息
- 连接后无数据传输
应对策略:
- 动态黑名单(IP/ClientID)
- 连接速率限制
- 异常断开报警
十、协议实现要点
10.1 网络传输要求
| 要求 | 说明 |
|---|---|
| 有序 | 报文必须按发送顺序到达 |
| 可靠 | 不丢失,不损坏 |
| 双向 | 客户端↔服务端双向通信 |
| 字节流 | 基于字节流而非消息 |
支持协议:TCP、TLS、WebSocket(不支持UDP)
10.2 连接处理流程

10.3 CONNACK返回码
| 返回码 | 描述 | 处理方式 |
|---|---|---|
| 0x00 | 连接已接受 | 正常继续 |
| 0x01 | 不支持的协议版本 | 断开连接 |
| 0x02 | 标识符不合格 | 断开连接 |
| 0x03 | 服务端不可用 | 断开连接 |
| 0x04 | 用户名或密码错误 | 断开连接 |
| 0x05 | 未授权 | 断开连接 |
十一、最佳实践建议
11.1 客户端设计
-
ClientID管理:固定ClientID以支持会话恢复
-
CleanSession选择:移动设备用1,关键业务用0
-
KeepAlive设置:根据网络状况调整(建议1-5分钟)
-
遗嘱机制:重要设备启用,用于异常检测
11.2 服务端设计
-
主题规划:使用层级结构,避免过度使用通配符
-
保留消息:谨慎使用,定期清理
-
安全策略:强制TLS,实施认证授权
-
监控告警:监控连接数、消息速率、异常行为
11.3 消息设计
-
QoS选择:数据重要性 vs 性能开销
-
主题设计:语义清晰,避免歧义
-
负载格式:使用JSON等标准格式
-
消息大小:控制单消息大小,避免阻塞
11.4 错误处理
// 协议违规处理原则
if (收到非法报文) {
关闭网络连接; // 根据规范必须断开
记录日志;
告警通知;
}
// 瞬时错误处理
if (处理报文时发生瞬时错误) {
关闭连接; // 如缓冲区满等
避免影响其他客户端;
}
十二、常见问题与解决方案
12.1 连接问题
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 频繁重连 | KeepAlive设置过短 | 适当延长KeepAlive |
| 连接被拒绝 | ClientID冲突 | 使用唯一ClientID |
| 认证失败 | 凭证错误 | 检查用户名密码 |
12.2 消息问题
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 消息丢失 | QoS=0网络差 | 升级为QoS 1或2 |
| 消息重复 | QoS=1网络不稳定 | 应用层去重,或使用QoS 2 |
| 接收延迟 | 服务端负载高 | 优化服务端,负载均衡 |
12.3 性能问题
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 高CPU使用 | 频繁发布订阅 | 合并消息,减少频率 |
| 内存增长 | 保留消息积累 | 定期清理,限制数量 |
| 网络拥塞 | 消息体过大 | 压缩,分片 |
附录:协议一致性要求速查表
| 项目 | 客户端要求 | 服务端要求 |
|---|---|---|
| 报文格式 | 必须符合规范 | 必须符合规范 |
| QoS支持 | 必须支持所有QoS等级 | 必须支持所有QoS等级 |
| 主题匹配 | 必须支持通配符 | 必须按规范匹配 |
| 会话管理 | 必须支持CleanSession | 必须支持会话状态 |
| 安全传输 | 推荐支持TLS | 必须支持有序可靠传输 |
| 错误处理 | 必须关闭非法连接 | 必须关闭非法连接 |