You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

MQTT订阅者使用QoS 2无法接收发布者QoS 0时的离线队列消息问题咨询

MQTT订阅者使用QoS 2无法接收发布者QoS 0时的离线队列消息问题咨询

你好呀,从你的测试场景和疑惑来看,核心是你对MQTT QoS的交互规则和QoS0的语义有些误解,我来帮你拆解清楚:

问题场景复盘

你做的两个测试结果其实一个符合规范、一个是你对规则的预期偏差:

  • ✅ 发布QoS2 + 订阅QoS2:订阅者离线时发消息,重新上线后收到队列消息——这完全符合MQTT规范
  • ❌ 发布QoS0 + 订阅QoS2:订阅者离线时发的消息,上线后收不到——这才是MQTT定义的正确行为,你的预期确实错了~

核心QoS规则解析

你对发布者/订阅者QoS的基础定义是对的,但漏掉了一个关键规则:

Broker对消息的持久化(用于离线队列)和最终交付的QoS等级,取发布者QoS订阅者QoS中的较小值,而且QoS0的消息本身就没有「离线队列」的语义。

具体到你的第二个测试场景:

  1. QoS0的语义是「至多一次,发送即忘」——发布者只把消息发出去,不管Broker有没有收到;Broker收到QoS0消息后,不会做任何持久化存储
  2. 哪怕订阅者用QoS2订阅,并且开启了cleanSession=false(持久会话),但因为原始消息是QoS0,Broker不会把它存入离线队列,只会在消息到达时推送给当时在线的订阅者。如果订阅者离线,这条消息就直接被Broker丢弃了,不会等到订阅者上线再推送。

而第一个测试中发布者用QoS2,Broker会为持久会话的订阅者存储这条消息,所以上线后能收到,这是完全符合规则的。

你的代码检查建议

从你贴的代码来看,订阅和发布的逻辑没有明显问题,但可以再确认两个细节:

  • 确保客户端的cleanSession确实被设置为false:比如Qt MQTT客户端初始化时,是否调用了client->setCleanSession(false)?有时候可能会在代码其他地方被意外覆盖,这点可以再排查下
  • 确认你的MQTT Broker支持持久会话:部分轻量Broker可能默认关闭了持久化功能,或者对QoS0的处理严格遵循规范(不存储),可以检查Broker的配置文档

结论

如果想要订阅者离线后上线能收到消息,发布者必须使用QoS1或QoS2——只有QoS1和QoS2的消息,Broker才会为开启了持久会话的订阅者存储离线队列,再结合订阅者的QoS等级做交付。QoS0的消息不管订阅者QoS多高,都不会进入离线队列哦。

你可以调整发布端的QoS等级再测试,应该就能得到你预期的结果啦😉

火山引擎 最新活动