【云Devops转行】【嵌入式开发学习】物联网-MQTT协议入门
提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档【云Devops转行】【学习嵌入式开发】物联网-MQTT协议入门1. 简介发布订阅特点基本概念EXMQMQTTX2. MQTT控制报文常见报文报文格式固定报头可变报头有效载荷3. QoSQoS消息质量等级4. 主题主题通配符系统主题5. 会话6. 消息保留消息消息过期间隔遗嘱消息延迟发布用户属性7. 订阅订阅选项QoSNo LocalRetain As PublishedRetain Handling共享订阅排他订阅自动订阅MQTT客户端编程注意事项单片机(MCU)环境下MQTT开发基于Linux芯片环境开发1. 简介MQTT是一种轻量级、发布/订阅模式的消息传输协议。它被设计用于低带宽、高延迟或网络不稳定的受限环境。学习资料B站尚硅谷发布订阅特点轻量级占用系统资源较少数据报文较小可靠性提供多种消息的质量等级安全性较强提供传输层、套接层的加密通讯双向通信MQTT客户端可发送数据也可从代理中获取Data多语言支持PHP、Node.js、Python、Go、java基本概念MQTT客户端运行MQTT客户端库的应用、设备MQTT Broker实现MQTT的代理软件主题Broker中一个普通字符串用于对消息的分类EXMQ一款大规模分布式物联网 MQTT 消息中间件是常用的 Broker 实现之一。默认用户/密码admin / public可在linux下docker搭建MQTTX客户端软件2. MQTT控制报文报文是 MQTT 协议在网络中交换和传输的最小数据块。常见报文报文格式固定报头 可变报头 有效载荷组成部分是否必须内容固定报头必不可少报文类型、标志位、长度可变报头可选报文特定信息如 Packet Identifier、主题名等有效荷载可选报文携带的实际数据如 PUBLISH 报文的消息体固定报头报文类型4 bit占4个bit位无符号整数。标识位4 bitBit 3 DUP表示当前PUBLISH报文是否是重传。Bit 21 QoS表示当前PUBLISH报文使用的服务质量等级。Bit 0Retain表示当前PUBLISH报文是否是保留消息。剩余长度MQTT报文长度 固定报头长度 剩余长度剩余长度 可变报头长度 有效载荷长度可变报头内容取决于具体报文类型举例CONNECT报文 协议名级别连接标识keep alive 属性PUBLISH报文主题名 报文标识 属性属性以属性长度 和 属性内容 的 Key-Value 形式出现提供了协议的扩展性。不同报文的属性取值不同用于传递元数据如会话过期时间、消息过期间隔、用户属性等。有效载荷用于实现对应报文的核心功能举例PUBLISH报文Payload用于承载具体的应用消息内容SUBSCRIBE报文Payload包含需要订阅的主题、对应订阅的选项3. QoSMQTT 底层使用 TCP 协议但 TCP 只能保证数据流不丢失不能保证应用程序级别的消息投递因此引入 QoS 机制。QoS消息质量等级QoS消息质量等级含义可靠性特点工作机制适用场景0做多发送一次最低。如果网络抖动、客户端掉线或服务器繁忙消息就会直接丢失开销最小延迟最低速度最快发送方把消息发出去就完事了不等待接收方的确认ACK也不会在本地持久化存储这条消息。对数据丢失不敏感的场景。例如实时传感器数据上报每秒都在发丢一两条无所谓、环境温湿度监控、在线状态心跳包1至少发送一次中等。能保证消息绝对不会丢但可能会重复在可靠性和性能之间取得了较好的平衡发送方发送消息后必须等待接收方返回PUBACK确认。如果超时没收到确认发送方会重新发送该消息允许少量重复但绝不能丢数据的场景。例如物联网设备状态变更通知、普通的告警推送、非关键性的业务日志2恰好一次发送不会丢失、不会重复网络开销最大延迟最高对服务器和客户端的性能要求也最高采用四次握手机制PUBLISH → PUBREC → PUBREL → PUBCOMP。不仅保证消息不丢还通过状态机确保消息绝不重复对数据准确性和唯一性要求极其严格的场景。例如金融交易结算、计费系统扣费、关键控制指令下发、订单状态流转在发送消息的时候可以指定消息质量等级一般broker获取到消息后会按照发送时指定的质量等级发送给订阅者。特殊情况订阅者指定了订阅消息的最大质量等级消息等级可能发生改变。4. 主题本质是一个UTF-8编码的字符串类似URL路径使用“/”分层不建议用“/”作为开头和结尾test/10/temperature不需要提前创建主题MQTT客户端在订阅、发布消息时自动创建主题通配符通配符使用示例匹配单个主题层级匹配的通配符a//c匹配a/b/c不匹配a/b/d/c 或 a//c。#匹配零个或多个层级必须放在主题过滤器的最后a/b/#匹配a/b/c、a/b/d/e、a/b系统主题以$SYS/开头的主题用于获取MQTT服务器自身运行状态、消息统计、客户端上下线事件等数据。特点 默认不允许远程客户端订阅取决于 Broker 配置通常用于监控 Broker 性能。用途获取集群状态、客户端连接/离线事件如$SYS/brokers//clients//connected等。详细使用见emqx文档5. 会话客户端与服务器之间的连接每个客户端可以启动一个或多个会话实现和服务器的消息传递。常见配置参数描述Clear Start决定是否复用旧会话Clean Start 0尝试复用旧会话基于 Client ID。如果旧会话存在则恢复其订阅和未完成的 QoS 消息。如果不存在则创建新会话Clean Start 1创建新会话。Broker 丢弃任何存储的旧会话状态包括旧订阅和未完成的 QoS 状态Session Expiry Interval (会话过期时间, MQTT 5.0)客户端断开连接后Broker 存储该会话的时长秒Session Expiry Interval 未指定或设置为 0客户端断开连接后会话立即过期并删除。6. 消息普通消息在发送前对应的主题如果不存在订阅者MQTT服务器会直接丢弃。保留消息可保留在MQTT服务器中任何新的订阅者订阅与保留消息中的主题匹配的主题时会立即接收到该消息。保留消息常见使用场景智能家居设备的状态只在变更时上报但控制端需要在上线后就能获取到设备状态传感器上报数据的间隔太长但是订阅者需要在订阅后立即获取到最新的数据传感器版本号、序列号等不会经常变更的属性在上线后发布一条保留消息告知后续的所有订阅者特点每一个主题最多只有一条保留消息即最后一条带有 Retain 标志的消息。客户端在建立新的订阅时Broker 会检查该主题是否有保留消息并立即发送给客户端。必须在保留消息发布之后客户端再订阅该主题才能收到。如果在保留消息发布前就已订阅收到的只是后续的普通消息。删除保留消息发送空内容的保留消息 发布一个 空载荷 且Retain True的消息到该主题。设置过期时间 在发布保留消息时设置Message Expiry Interval使其在达到时间后自动失效。保留消息独立于会话。 即使使用Clean Start 1创建新会话只要你重新订阅了该主题Broker 依然会发送保留消息。消息过期间隔通过Session Expiry Interval为离线客户端缓存未发送的消息然后在客户端恢复连接时发送但如果客户端离线时间较长可能有一些寿命较短的寿命已经没有必要发送给客户端了避免浪费网络带宽和客户端资源。默认情况下消息中不包含消息过期间隔表示永不过期。遗嘱消息客户端在连接时在服务端中注册一个遗嘱消息当客户端意外断开连接服务端就会向其他订阅了相应主题的客户端发送此遗嘱消息接收者可以及时采取行动例如向用户发送通知、切换备用设备等。遗嘱消息的设置发生在客户端发送CONNECT 报文时。触发 客户端意外断开连接如Keep Alive 超时、网络错误。Broker 会发布遗嘱消息。不触发 客户端正常关闭发送DISCONNECT报文或 Broker 正常关闭且客户端没有持久会话需要保留。字段名称作用说明是否必需Will Flag (遗嘱标志)设置为 1表示客户端想要设置一个遗嘱消息。是 (开启功能)Will Topic (遗嘱主题)指定当客户端非正常断开连接时Broker 应该将遗嘱消息发布到哪个主题上是Will Payload (遗嘱载荷)指定遗嘱消息的具体内容数据是Will QoS (遗嘱 QoS 等级)指定 Broker 发布遗嘱消息时应使用的 QoS 等级是Will Retain (遗嘱保留标志)设置为 1表示 Broker 发布遗嘱消息后应将其作为保留消息存储可选Will Delay Interval (遗嘱延迟发送)客户端断开连接后延迟多久发布遗嘱消息秒期间重连恢复则不会发布可选延迟发布MQTT服务器收到发布者的消息后延迟一段时间后再转发给订阅者使用场景定时发送提醒、在特定时间点发布调度任务主题格式$delay/{DelayInterval}/{TopicName}$delay/是前缀。{DelayInterval}延迟时间间隔单位为秒。{TopicName}消息最终要发布的实际主题。用户属性允许在Publish、Subscribe、Connect、Disconnect等报文中携带附加信息类似于http协议请求头。应用场景日志记录在发布和订阅报文中加入用户属性帮助记录操作者信息、操作时间、原因说明等消息分类标记用来给消息添加标签、分类如消息类型等便于接收方进行过滤、排序、处理。7. 订阅订阅选项订阅组成主题过滤器决定服务端将要向我们转发哪些主题下的消息订阅选项是允许我们进一步定制服务端的转发行为QoS、No Local、Retain As Published、Retain HandlingQoS表示服务端在向订阅端发送消息时可以使用的最大QoS等级情况1服务端支持最大QoS 客户端订阅时请求的最大QoS情况2订阅时请求的最大QoS 发布时的QoSNo Local取值0默认值服务端可以将消息转发给发布这个消息的客户端1不可以常用于桥接场景桥接本质是两个MQTT Server建立一个MQTT连接相互订阅一些主题Server将客户端消息转发给另一个Server另一个Server则将消息继续转发给他的客户端。没有设置为1则会在Server之间来回转发导致转发风暴Retain As Published取值0默认值 服务端在向订阅者转发消息时需要清除Retain标识1 服务端在向订阅者转发消息时需要保持Retain标识不变用于桥接相互告知是保留消息避免保留标识在server间互传时丢失。Retain Handling用于向服务端指示当订阅建立时是否需要发送保留消息取值0默认值 只要订阅建立就发送保留消息1 只有建立全新订阅而不是重复订阅时发送保留消息2订阅建立时不发送保留消息共享订阅普通订阅每发布一条消息所有匹配的订阅者都会收到消息的副本。当订阅者Subscriber消费速度无法跟上消息Publisher生产速度达到瓶颈。共享订阅使MQTT服务端在使用特定订阅的客户端之间均衡地分配消息负载。提高吞吐量、形成高可用共享订阅分类前缀格式示例前缀真实主题名称流程带群组格式$share/abc/t/1$share/abct/1不带群组格式$queue/t/1$queuet/1负载均衡算法通过DashBoard进行配置随机、轮询、哈希、粘性、本地优先排他订阅共享订阅的一种特殊形式用于保证单一处理者和自动故障转移一个主题同一时刻仅允许一个订阅者存在。$exclusive/t/1前缀$exclusive主题t/1错误码0x8F使用了$exclusive但未开启排他0x97已被订阅自动订阅在设备连接后按照规则为其订阅指定主题不需要额外发起订阅。MQTT客户端编程注意事项单片机(MCU)环境下MQTT开发硬件与网络接入Wi-Fi 模块如 ESP8266、ESP32。通过 UART串口发送 AT 指令来建立 TCP 连接。4G 模块如 SIM800 系列。同TCP/IP 协议栈MCU 只需操作寄存器即可。软件协议栈实现在 MCU 上你通常无法运行完整的 MQTT 库使用嵌入式轻量级 C 库业界最常用的是 Paho MQTT Embedded C 库。它专门针对资源受限设备优化仅包含 MQTT 数据包的序列化与反序列化功能内存占用极低。手动构造报文裸机开发如果资源极端受限开发者需要手动拼接 MQTT 协议的十六进制报文如 CONNECT、PUBLISH、SUBSCRIBE 报文并通过串口发送给网络模块。核心开发步骤配置网络通过 AT 指令连接 Wi-Fi/4G并建立到 MQTT Broker如 EMQ X、阿里云 IoT的 TCP 连接。MQTT 握手与保活发送 MQTT CONNECT 报文进行身份认证ClientID、Username、Password并启动定时器发送 PINGREQ 心跳包以保持连接。业务逻辑通过定时器或事件触发调用 PUBLISH 报文上报传感器数据通过解析接收缓冲区的数据处理服务端下发的控制指令。基于Linux芯片环境开发拥有完整的操作系统、丰富的内存和标准的 TCP/IP 协议栈。开发的核心原则是“调用标准库”和“异步事件驱动”。直接使用客户端库。以C语音为例步骤环境准备在 Linux 系统中安装libmosquitto-dev库或者在交叉编译工具链中配置该库初始化与连接调用mosquitto_lib_init()初始化库创建实例mosquitto_new()设置回调函数如连接成功回调、消息接收回调mosquitto_connect_callback_set()连接到Broker mosquitto_connect()订阅与发布订阅主题mosquitto_subscribe()发布消息mosquitto_publish()事件循环Linux 下的 MQTT 库是基于异步事件的。你必须调用mosquitto_loop_start()开启后台线程处理网络事件或mosquitto_loop_forever()阻塞式循环来维持网络通信编译与运行使用 GCC 或交叉编译器如 aarch64-linux-gnu-gcc编译代码链接 -lmosquitto库生成可执行文件后在开发板上运行由于多python更熟悉开发更敏捷后续开发过程准备使用如下方式Python写MQTT业务逻辑python库paho-mqtt C语言处理底层驱动提高资源使用率和数据处理性能由python调用C的方式处理底层内容。