物联网笔记——ESP32-QoS笔记
MQTT QoS 0 / 1 / 2 学习笔记1. QoS 是什么QoS 全称Quality of Service服务质量等级它决定 MQTT 消息传输时需要保证到什么程度。MQTT 一共有三个 QoS 等级QoS 0At most once QoS 1At least once QoS 2Exactly once可以简单理解为QoS 0最多一次 QoS 1至少一次 QoS 2恰好一次2. QoS 02.1 工作流程QoS 0 最简单ESP32 Broker PUBLISH --------------------------发送完成后不等待 MQTT 层的发布确认。没有PUBACK因此QoS 0 发送一次 不等待 MQTT ACK 不进行 MQTT 层确认2.2 特点优点通信开销小 速度快 实现简单缺点消息可能丢失因此适合温度 湿度 光照 RSSI 实时位置 高频状态数据这些数据通常会持续刷新偶尔丢失一条影响不大。2.3 注意QoS 0 不等于完全没有 ACKMQTT 通常运行在MQTT ↓ TCP ↓ IPQoS 0 没有的是MQTT 层 PUBACK但是 TCP 自己仍然存在TCP ACK TCP 重传 数据排序 流量控制因此QoS 0 MQTT PUBACK ❌ TCP ACK ✅不能把 MQTT ACK 和 TCP ACK 混在一起。3. ESP-IDF 中的 QoS 0ESP-IDF 发布函数esp_mqtt_client_publish(client,topic,data,len,qos,retain);例如intmsg_idesp_mqtt_client_publish(event-client,esp32/test,hello esp32,0,0,0);其中0// QoS表示QoS 0实际实验中publish msg_id: 0这是正常现象。QoS 0 不需要使用 Packet Identifier 来跟踪后续 PUBACK因此 ESP-IDF 中 QoS 0 发布的msg_id为 0。4. QoS 1QoS 1 的目标是At least once 至少一次也就是说尽量确保消息不会因为一次传输失败直接消失。4.1 QoS 1 工作流程ESP32 Broker PUBLISH msg_id 20019 -------------------------- PUBACK msg_id 20019 --------------------------QoS 1 比 QoS 0 多了PUBACK即Publish Acknowledgement 发布确认5. msg_id 的作用例如 ESP32 发布msg_id 20019Broker 返回PUBACK msg_id 20019这样 ESP32 就知道Broker 确认的是 20019 这条消息。如果同时发送消息A → msg_id 100 消息B → msg_id 101 消息C → msg_id 102Broker 返回PUBACK 101ESP32 就知道101 已确认而不是其他消息。所以msg_id的重要作用就是发送消息 ↓ 分配 msg_id ↓ 等待 ACK ↓ 通过相同 msg_id 匹配确认6. ESP-IDF 中实际验证 QoS 1将qos0修改成qos1例如intmsg_idesp_mqtt_client_publish(event-client,esp32/test,hello esp32,0,1,0);实际运行得到publish msg_id: 20019说明 QoS 1 已经获得实际的消息 ID。7. MQTT_EVENT_PUBLISHED为了确认 Broker 是否真的确认消息可以增加elseif(event_idMQTT_EVENT_PUBLISHED){esp_mqtt_event_handle_tevent(esp_mqtt_event_handle_t)event_data;printf(MQTT Publish ACK, msg_id:%d\n,event-msg_id);}实际运行publish msg_id: 20019 MQTT Publish ACK, msg_id:20019两个 ID 一样20019 20019说明ESP32 ↓ PUBLISH 20019 ↓ Broker ↓ PUBACK 20019 ↓ ESP-IDF ↓ MQTT_EVENT_PUBLISHED因此MQTT_EVENT_PUBLISHED可以理解为对于这条 QoS 1 消息Broker 已经完成 MQTT 层确认。8. MQTT ACK 不等于设备执行成功这是工程中很重要的一点。假设发送{cmd:motor_stop}收到 MQTT ACK只能证明Broker 已确认 MQTT 消息不能证明电机真的停止了如果业务要求确认设备动作则应该服务器 ↓ MQTT CMD ↓ ESP32 ↓ 控制硬件 ↓ 读取实际状态 ↓ MQTT STATE ↓ 服务器也就是通信确认 ≠ 设备动作确认9. 为什么 QoS 1 还可能重复假设ESP32 Broker PUBLISH 20019 -------------------------- 已收到Broker 已收到消息并准备发送PUBACK 20019但是网络出现问题PUBACK 20019 ------------- X此时Broker我已经收到 20019ESP32我没收到 20019 的 PUBACKESP32不能确定消息是否到达因此可能重新发送。于是第一次 PUBLISH 20019 第二次 PUBLISH 20019所以 Broker 一侧可能遇到重复消息。因此QoS 1 至少一次不是恰好一次10. DUP 重发标志MQTT 的 PUBLISH 报文中存在DUP即Duplicate 重复发送第一次发送DUP 0需要重发时DUP 1可以理解为第一次 PUBLISH QoS 1 DUP 0 msg_id 20019重发PUBLISH QoS 1 DUP 1 msg_id 2001911. 幂等性因为 QoS 1 可能重复所以 IoT 控制命令最好具有幂等性含义同一个操作执行一次和执行多次最终结果相同。例如gpio_set_level(GPIO_LED,1);执行1次 → LED ON 10次 → LED ON最终状态一样。这就是幂等。推荐设计推荐set_led ON重复ON ON ON结果仍然ON不推荐toggle_led重复两次OFF → ON ON → OFF最后状态完全不同。所以实际 IoT 系统中设置目标状态通常比执行一次翻转更加适合作为远程控制命令。12. QoS 2QoS 2 的目标是Exactly once 恰好一次主要解决 QoS 1 可能重复的问题。QoS 2 是 MQTT 中最高的服务质量等级。13. QoS 2 四步流程完整流程ESP32 Broker PUBLISH -------------------------- PUBREC -------------------------- PUBREL -------------------------- PUBCOMP --------------------------四个阶段PUBLISH PUBREC Publish Received PUBREL Publish Release PUBCOMP Publish Complete14. QoS 2 为什么需要这么复杂假设msg_id 23984首先发送PUBLISH 23984Broker 收到后记录 23984 已收到然后返回PUBREC 23984即我已经收到并记录这条消息。ESP32 收到 PUBREC 后不再继续重复发送原始 PUBLISH而是进入下一阶段PUBREL 23984Broker 完成处理以后PUBCOMP 23984整个事务才结束。15. QoS 2 的核心思想可以理解为两个阶段。第一阶段你真的收到并记住了吗 ↓ PUBREC第二阶段既然已经记住 现在完成这次消息处理。 ↓ PUBREL ↓ PUBCOMP因此 Broker 即使再次收到相同 QoS 2 消息也能够根据保存的状态识别这是之前的消息而不是再次作为新的应用消息处理。16. ESP-IDF 中使用 QoS 2只需要修改qos2例如intmsg_idesp_mqtt_client_publish(event-client,esp32/test,hello esp32,0,2,0);不需要自己实现PUBREC PUBREL PUBCOMP这些 MQTT 协议流程由ESP-MQTT内部处理。程序仍然通过MQTT_EVENT_PUBLISHED知道这次发布流程已经完成。实际实验结果publish msg_id: 23984 MQTT Publish ACK, msg_id:23984说明此次 QoS 2 发布正常完成。17. QoS 0 / 1 / 2 对比QoS含义确认机制是否可能丢是否可能重复开销QoS 0最多一次无 MQTT PUBACK是一般不会因 MQTT 重传产生重复最低QoS 1至少一次PUBACK尽量避免是中QoS 2恰好一次PUBREC → PUBREL → PUBCOMP尽量避免MQTT 协议层避免重复交付最高18. 常见选择方法高频传感器数据例如temperature humidity light RSSI通常可以考虑QoS 0原因下一条数据很快就会刷新 偶尔丢失影响较小普通控制命令例如LED ON Relay OFF Set temperature 26通常可以考虑QoS 1同时使用幂等命令 必要时增加 command_id 业务层去重QoS 1 在很多 IoT 场景中是可靠性和开销之间比较常见的折中方案。对重复非常敏感的 MQTT 消息才考虑QoS 2因为通信次数更多 协议状态更多 资源开销更大所以QoS 并不是越高越好而是根据业务可靠性要求选择。19. 当前 ESP32 代码中的两个 QoS发布esp_mqtt_client_publish(event-client,esp32/test,hello esp32,0,1,0);这里QoS 1控制的是ESP32 发布esp32/test消息时使用什么 QoS。订阅esp_mqtt_client_subscribe(event-client,esp32/led,0);这里最后的0同样代表 QoS。表示ESP32 对esp32/led这个订阅请求使用 QoS 0。因此发布 QoS 和订阅 QoS 要分开理解。20. 本节必须记住的内容第一条QoS 0 最多一次 没有 MQTT PUBACK第二条QoS 1 至少一次 PUBLISH PUBACK 可能重复第三条QoS 2 恰好一次 PUBLISH PUBREC PUBREL PUBCOMP第四条msg_id 用于对应 MQTT 消息和确认流程第五条MQTT_EVENT_PUBLISHED QoS 1 / QoS 2 发布已经得到相应协议确认并完成第六条QoS 1 可能重复 → 控制命令尽量设计成幂等第七条MQTT ACK ≠ 设备实际动作完成第八条QoS 不是越高越好 而是可靠性、实时性、网络开销之间的权衡

相关新闻

mcp-for-beginners 实战:用 Python 低层 Server 构建可扩展的 MCP 工具服务并完成端到端运行验证

mcp-for-beginners 实战:用 Python 低层 Server 构建可扩展的 MCP 工具服务并完成端到端运行验证

教程文档人工智能 【免费下载链接】mcp-for-beginners This open-source curriculum introduces the fundamentals of Model Context Protocol (MCP) through real-world, cross-language examples in .NET, Java, TypeScript, JavaScript, Rust and Python. Designed for deve…

2026/10/10 0:45:45 阅读更多 →
剪映数字人长句口型不齐:先核原声和断句,再比较同一句修改结果

剪映数字人长句口型不齐:先核原声和断句,再比较同一句修改结果

园艺课数字人讲一段较长说明,嘴部动作和声音明显不齐,可以先核文稿、原声与画面各自状态,再在当前支持范围内试断句或语速。调整文稿可能改善表达,但不能保证所有嘴部问题都随之修复,最终仍要看实际音画。剪映有数字人…

2026/10/10 0:45:46 阅读更多 →
猎头多平台寻访繁琐,聘小助7×24小时自动触达能力如何?

猎头多平台寻访繁琐,聘小助7×24小时自动触达能力如何?

猎头与招聘团队在多平台寻访候选人时,常面临账号切换、重复搜索、逐个打招呼、消息跟进遗漏、非工作时段响应慢等问题。若工具能实现自动触达与AI初筛,确实可能压缩重复劳动。但“效率提升”不能只看宣传,需要从可验证信息、功能边界、数据合…

2026/10/10 0:46:49 阅读更多 →

最新新闻

MCP、A2A、AG-UI、ANP、ACP 五大协议怎么选?万字长文拆解 AI 智能体通信协议全景与 TaoToken 统一接入实践

MCP、A2A、AG-UI、ANP、ACP 五大协议怎么选?万字长文拆解 AI 智能体通信协议全景与 TaoToken 统一接入实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 0:52:26 阅读更多 →
LVS负载均衡集群核心原理与高可用实践:三种模式、调度算法与Keepalived详解

LVS负载均衡集群核心原理与高可用实践:三种模式、调度算法与Keepalived详解

本文不聊配置命令的复制粘贴,而是把LVS负载均衡集群这套理论完整梳理一遍。适合刚接触集群概念、准备做负载均衡选型、或者面试前想把LVS彻底搞明白的读者。我会把三种工作模式、调度算法、高可用机制这些核心内容讲透,同时穿插一些实际部署中的取舍和坑…

2026/10/10 0:52:26 阅读更多 →
铁制品腐蚀缺陷检测YOLO数据集:开箱即用,省去标注与划分

铁制品腐蚀缺陷检测YOLO数据集:开箱即用,省去标注与划分

简介:这份资源面向从事工业质检、缺陷检测方向的算法工程师与深度学习学习者,提供铁制品表面腐蚀缺陷的YOLO格式目标检测数据集,可直接用于YOLOv5等框架的训练与验证。数据按YOLOv5标准目录组织,类别仅含corrosion一类&#xff0c…

2026/10/10 0:52:26 阅读更多 →
PHP集成活体识别:V步骤1实现可审计合规验证

PHP集成活体识别:V步骤1实现可审计合规验证

1. 项目概述:为什么PHP项目现在必须嵌入活体识别能力最近三个月,我连续接手了三个不同行业的风控系统改造需求——某在线教育平台的教师资质核验、某本地生活服务平台的骑手身份绑定、还有某金融信息中介的用户实名认证环节。它们表面业务差异很大&#…

2026/10/10 0:52:25 阅读更多 →
Ubuntu 22.04 实时内核打造指南:PREEMPT_RT 补丁完整实操

Ubuntu 22.04 实时内核打造指南:PREEMPT_RT 补丁完整实操

开发自己的 Ubuntu 22.04 实时内核发行版:一次完整打 RT 补丁的实操记录这两年做数据采集和机器人的项目越来越多,现场调试时遇到最多的一个问题,就是“为什么我 ping 一下走个网络,电机控制就抖了一下?”说白了&#…

2026/10/10 0:52:25 阅读更多 →
为什么 qwen 3.7 flash 评论很少?从 API 调用日志看真实使用门槛

为什么 qwen 3.7 flash 评论很少?从 API 调用日志看真实使用门槛

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 0:51:25 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →