如何在 eclipse-mosquitto 中使用 QoS MQTT 接收离线客户端的消息?

How to recieve messages for offline clients using QoS MQTT in eclipse-mosquitto?

我的 mosquitto.conf 是(这是整个 conf 文件,因为其他所有内容都被注释掉了)

log_dest file /mosquitto/log/mosquitto.log
log_type all
connection_messages true
log_timestamp true
log_timestamp_format [%H:%M:%S]
persistence true
persistence_location /mosquitto/data/
listener 1883
listener 9001
protocol websockets

然后我运行

docker exec -it ecs-Eclipse_mosquitto_MQTT-11-Eclipse-mosquitto-MQTT-eafxxxxxxx mosquitto_pub -t presence -m hellothere -q qos=2

(注意我还没有在线的活跃订阅者)

导航到 /mosquitto/data,确实有一个名为 mosquitto.db

的文件

所以我可以推断出我的消息 hellothere 存储在 mosquitto.db

然后我运行命令

docker exec -it ecs-Eclipse_mosquitto_MQTT-11-Eclipse-mosquitto-MQTT-eafxxxxxxx mosquitto_sub -t presence -q qos=2

我期待什么

用于 MQTT 代理发送存储的消息,因为订阅者现在在线

实际发生了什么

无限期等待消息

也许我遗漏了什么?

我认为 mqtt spec 的相关位是:

When a Server takes ownership of an incoming Application Message it MUST add it to the Session state of those clients that have matching Subscriptions.

在您的情况下,当消息发布时,没有具有匹配订阅的客户端(因为此时您还没有 运行 mosquitto_sub),因此它什么也不做。

如果您希望为某个客户端存储消息,您必须首先作为该客户端连接并订阅相关主题(QOS>0 且 CleanSession=0)。这样做之后,客户端离线时收到的任何消息都将在重新连接时存储和传递(只要 CleanSession=0)。

注意:要使用 mosquitto_sub 执行上述操作,您需要使用 --id 参数来设置客户端 ID(消息只会为订阅了相关内容的特定客户端排队话题)。您还需要 -c 标志来禁用 'clean session' 标志。

所以步骤如下(我已经删除了额外的 docker 位 - 您可以将它们添加回去):

mosquitto_sub -c --id subscriber1 -t presence -q 2

这将订阅然后等待任何消息;您可以安全地关闭它(这是需要发生的订阅位)。接下来发布您的消息:

mosquitto_pub -t presence -m hellothere -q 2

现在您可以再次开始 mosquitto_sub 以检索存储的消息:

mosquitto_sub -c --id subscriber1 -t presence -q 2

警告:当您这样订阅时,经纪人将存储您离线时收到的任何消息。如果您正在测试处理大量消息的代理(因为存储所有消息需要 space),这可能会成为一个问题。这里可能不是问题,因为你只是在测试,但要记住一些事情...... 运行 mosquitto_sub 没有 -c 将清除任何订阅 - mosquitto 配置中也有选项允许您限制保留消息的数量和保留时间。

MQTT 不是这样工作的。

消息只为之前连接过的客户端排队,它是一个pub/sub系统而不是消息队列系统。

客户端需要在过去连接并订阅了相关消息的主题。然后,在将 cleanSession 标志设置为 false 并使用相同的客户端 ID 发布消息后,它需要重新连接。

您可以在 HiveMQ 博客上阅读更多相关信息 here