嵌入式设备上mqtt库的使用
一、MQTT 使用场景
设备遥测:周期/事件上报传感器数据(温度、湿度、电量…)。
命令下发:云端/网关向设备发送配置、固件升级指令。
状态可观测:上线/离线、告警、运行统计;出生消息(Birth)与遗嘱(LWT)让运维可见。
多对多解耦:发布-订阅模型天然支持多生产者、多消费者,云侧可用共享订阅做水平扩展。
弱网友好:KeepAlive 心跳、QoS 等级、持久会话、离线排队(由 Broker 侧会话/队列承担)等机制,让“断了也能续”。
二、MQTT 报文格式(速览)
2.1 格式说明
一条 MQTT 报文 = 固定头 + 可变头 + 负载:
固定头(Fixed header):1 字节类型与标志(如 PUBLISH 的 DUP/ QoS/ RETAIN)+ Remaining Length(变长编码,最多 4 字节)。
可变头(Variable header):随报文类型不同而不同。
例如 CONNECT 可变头含协议级别、KeepAlive、连接标志;
PUBLISH 可变头含主题名、(QoS>0 时) Packet Identifier。
负载(Payload):报文具体内容。
CONNECT 的负载是 ClientID、用户名/密码、LWT 消息体;
PUBLISH 的负载是应用数据(二进制任意字节)。
时序(最常用几类):
CONNECT → CONNACK
SUBSCRIBE → SUBACK
PUBLISH(QoS0/1/2):
QoS0:直接发
QoS1:PUBLISH → PUBACK
QoS2:PUBLISH → PUBREC → PUBREL → PUBCOMP
PINGREQ → PINGRESP(心跳维持)
DISCONNECT(优雅断开)
2.2 原始报文解析
2.3 示例一:CONNECT(含用户名/密码 + 遗嘱 LWT,KeepAlive=60s)
原始报文(hex dump)
10 38 // 固定头: Type=CONNECT(0x10), Remaining Length=0x38(56)
00 04 4D 51 54 54 // 可变头: 协议名 "MQTT"
04 // 协议级别: 4 = MQTT 3.1.1
CE // 连接标志(0xCE): 用户名/密码/遗嘱QoS1/CleanSession
00 3C // KeepAlive=0x003C=60秒
00 06 63 6C 69 31 32 33 // 负载: ClientID="cli123"
00 06 73 74 61 74 75 73 // 负载: Will Topic="status"
00 10 7B 22 6F 6E 6C 69 6E 65 22 3A 66 61 6C 73 65 7D // 负载: Will Message={"online":false}
00 04 75 73 65 72 // 负载: Username="user"
00 04 70 61 73 73 // 负载: Password="pass"
字段拆解与说明
固定头
0x10:类型=CONNECT。
0x38:Remaining Length=56(变长编码;本例仅 1 字节即可)。
可变头
00 04 ‘M’‘Q’‘T’‘T’:协议名“MQTT”。
04:协议级别=4(即 v3.1.1)。
CE(二进制 1100 1110):
bit7 Username=1
bit6 Password=1
bit5 Will Retain=0
bit4…3 Will QoS=01(QoS1)
bit2 Will Flag=1
bit1 Clean Session=1
bit0 保留=0
00 3C:KeepAlive=60s。
负载(Payload)
ClientID:“cli123”
Will Topic:“status”
Will Message:{“online”:false}(注:长度 不含 字符串结尾 \0)
Username / Password:“user” / “pass”
计算校验:可变头长度=10;负载长度=8(ClientID)+8(WillTopic)+18(WillMsg)+6(User)+6(Pass)=46;合计 10+46=56,与 RL=0x38 一致。
2.4 示例二:PUBLISH(QoS1,Topic=sensors/temp,Payload=“23.6”)
原始报文(hex dump)
32 14 // 固定头: Type=PUBLISH(0x3), DUP=0 QoS=1 RETAIN=0 → 0x32;RL=0x14(20)
00 0C 73 65 6E 73 6F 72 73 2F 74 65 6D 70 // 可变头: 主题名 "sensors/temp" (长度=12)
00 0A // 可变头: Packet Identifier=10(QoS>0 必有)
32 33 2E 36 // 负载: ASCII "23.6"
字段拆解与说明
固定头首字节 0x32:
高 4 位=0x3(PUBLISH),低 4 位标志:DUP=0、QoS=01、RETAIN=0。
Remaining Length 0x14=20:= 主题(2+12) + PacketId(2) + 负载(4)。
可变头
主题长度 0x000C + sensors/temp。
Packet Identifier=0x000A(仅 QoS1/2 序列化)。
负载:“23.6”(4 字节;不要把 \0 计入)。
三、MQTT 不同版本区别(v3.1.1 vs v5,工程取舍)
主题 | v3.1.1 | v5(增强点) |
---|---|---|
会话控制 | Clean Session (二选一) | Clean Start + Session Expiry (可精确设置持久会话时长) |
背压/流控 | 无 | Receive Maximum (限制并发未 ACK 数)、Maximum Packet Size (限大包) |
诊断 | 返回码较粗 | Reason Code + Properties(失败原因更明确) |
请求-响应 | 自定义(如 corrId) | Response Topic + Correlation Data 原生支持 |
时效 | 仅 Retain | Message Expiry (过期不投递)、Will Delay (延迟遗嘱) |
省字节 | 无 | Topic Alias (长主题省流量) |
选择建议: |
MCU/RTOS 资源紧、库成熟度优先 → v3.1.1 足够。
需要弱网背压/过期控制/更强诊断 → 评估 v5(wolfMQTT 支持 v5,但实现/内存更复杂)。
四、wolfMQTT 接口概述(常用)
wolfMQTT 将每类报文封装为对应结构体;你填字段 → 库编码发送,收包通过回调/等待接口分发
4.1 初始化/网络
MqttClient_Init():创建客户端、设置收发缓冲与超时、注册消息回调。
MqttClient_NetConnect() / MqttClient_NetDisconnect():TCP/TLS 建连/断开(TLS 走 wolfSSL)。
(可选)MqttClient_SetPropertyCallback():v5 属性回调;MqttClient_SetDisconnectCallback():断连回调。
4.2 连接/会话
MqttClient_Connect(&MqttConnect):发送 CONNECT,等待 CONNACK。
MqttClient_Disconnect() / …Disconnect_ex:优雅断开(v5 可带原因码/属性)。
4.3 订阅/发布
MqttClient_Subscribe(&MqttSubscribe) / MqttClient_Unsubscribe(&MqttUnsubscribe) → SUBSCRIBE/UNSUBSCRIBE。
MqttClient_Publish(&MqttPublish):发布消息(QoS0/1/2)。
4.4 循环/心跳
MqttClient_WaitMessage(timeout_ms):等待入站报文,内部也维护 KeepAlive。
MqttClient_Ping() / …Ping_ex:主动发送心跳(通常不必手动调,WaitMessage 会处理)。
4.5 关键结构体字段对照(节选):
MqttConnect:client_id、keep_alive_sec、clean_session(v3)、username/password、will(含 topic/qos/retain/message)。
MqttSubscribe:topics[i].topic_filter + topics[i].qos。
MqttPublish:topic_name、qos、retain、dup、packet_id(QoS>0)、buffer/total_len。
v5 属性通过属性回调或扩展结构设置/读取(如 Receive Maximum、Message Expiry 等)。
五、wolfMQTT 接口使用(步骤与要点)
5.1 准备缓冲与回调
预留 TX/RX 缓冲(例如 1–4 KB 视负载大小);注册消息回调用于处理入站 PUBLISH。
5.2 网络建连(TCP/TLS)
若使用 TLS:准备 CA/设备证书与私钥(wolfSSL),并启用主机名校验(SNI)。
5.3 构造 CONNECT(v3.1.1)
ClientID:设备唯一标识;
KeepAlive:30–60s 常用;
Clean Session:量产建议 0(持久会话);
LWT:配置 will(topic/qos/retain/message),异常掉线时由 Broker 代发离线消息;
用户名/密码:按云服务鉴权规范设置(或使用 TLS 双向证书)。
5.4 订阅业务主题
设备通常订阅自己的命令主题(如 tenant/prod/dev/{id}/cmd/#)与必要的回复主题。
可一次订多个,wolfMQTT 的 MqttSubscribe