学习笔记——MQTT协议

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";   // 遗嘱消息内容

触发条件

  1. 网络I/O错误或故障

  2. Keep Alive超时

  3. 客户端非正常断开

  4. 协议错误导致连接关闭

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 重传规则

  1. 重传条件:在相同Session内等待确认超时

  2. DUP标志:重传时设置为1

  3. Packet ID重用:确认完成后可重用

  4. 顺序保证:必须按原始顺序重传

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 保留消息特性

  1. 单主题单消息:每个主题最多一个保留消息

  2. 零字节清理:发送零字节保留消息可清除

  3. 存储限制:服务端内存紧张时可丢弃

  4. 遗嘱保留: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 客户端设计

  1. ClientID管理:固定ClientID以支持会话恢复

  2. CleanSession选择:移动设备用1,关键业务用0

  3. KeepAlive设置:根据网络状况调整(建议1-5分钟)

  4. 遗嘱机制:重要设备启用,用于异常检测

11.2 服务端设计

  1. 主题规划:使用层级结构,避免过度使用通配符

  2. 保留消息:谨慎使用,定期清理

  3. 安全策略:强制TLS,实施认证授权

  4. 监控告警:监控连接数、消息速率、异常行为

11.3 消息设计

  1. QoS选择:数据重要性 vs 性能开销

  2. 主题设计:语义清晰,避免歧义

  3. 负载格式:使用JSON等标准格式

  4. 消息大小:控制单消息大小,避免阻塞

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 必须支持有序可靠传输
错误处理 必须关闭非法连接 必须关闭非法连接
相关推荐
Dev7z5 分钟前
基于MATLAB图像处理的苹果品质自动分级系统设计与实现
开发语言·图像处理·matlab
源代码•宸10 分钟前
Golang基础语法(go语言指针、go语言方法、go语言接口、go语言断言)
开发语言·经验分享·后端·golang·接口·指针·方法
Bony-10 分钟前
Golang 常用工具
开发语言·后端·golang
Paul_092011 分钟前
golang编程题
开发语言·算法·golang
csbysj202011 分钟前
Go 语言变量作用域
开发语言
牛奔14 分钟前
GVM:Go 版本管理器安装与使用指南
开发语言·后端·golang
四谎真好看14 分钟前
JavaWeb 学习笔记(Day02)之Vue
笔记·学习·vue·学习笔记·javaweb
百***787516 分钟前
2026 优化版 GPT-5.2 国内稳定调用指南:API 中转实操与成本优化
开发语言·人工智能·python
南屿欣风21 分钟前
Sentinel 资源异常处理优先级笔记
spring boot·笔记·sentinel
腥臭腐朽的日子熠熠生辉25 分钟前
nest js docker 化全流程
开发语言·javascript·docker