Mosquitto QoS2 错误 - 或微妙的规范解释?
Mosquitto QoS2 bug - or subtle spec interpretation?
谁能解释为什么此 MQTT QoS 消息从未发送过?
答案:需要在 conf 文件中设置 persistent true,然后出现确切的预期行为。
更多详情
我有一个简单的问题(尽管起始条件很复杂)。如果答案是“是”,那么 mosquitto 中就有一个错误,如果是“否”,那么它是对规范的一个非常微妙的解释,我(我怀疑很多其他人)没有完全理解。在第二种更有可能的情况下,这意味着不可能在单个设备上使用 sub 和 pub 对同一主题编写完全符合 QoS2 的“序列测试器”。
设置
订阅 T @ QoS2 并每次都启动 clean==false 的代码。每 1 秒发布一个整数值递增的 T,这样在正常操作过程中,事件顺序为:
- 客户端->服务器TX 1
- 服务器酒吧 1
- RX 1
- TX 2
- 服务器酒吧 2
- RX 2
等等
然后我故意随机中断与服务器的连接,以测试我的恢复程序。
重新启动时,我的测试客户端正确识别失败的 TX,因为它已存储状态,例如TX3 失败并重新发送,当然还有 mosquitto re-acks ...无论术语如何,如果中断在 TX 4 路的中间,我的代码恢复正确,如果它在 RX 4 的中间-way 然后 mosquitto 立即“恢复”它自己的失败 TX,一切都按预期进行。我从来没有得到 N 的任何“遗漏”值,并且我声明我的代码完全有效。那么我的问题是什么?
连接中断/重启行为异常
考虑 TX 和服务器 pub 之间的连接何时中断(我的下一个 RX 是什么),即 TX3 完全成功 PUB/REC/REL/COMP,如果没有中断,我将打印“RX 3”。接下来我使用 mqtt-spy 来发布 T[666]。然后我重新启动我的客户端。我得到的第一件事是来自服务器的 666 消息,这对我来说听起来很正确并且似乎同意:
当服务器获得传入应用程序消息的所有权时,它必须将其添加到具有匹配订阅的那些客户端的会话状态中。匹配规则在第 4.7 节 [MQTT-4.5.0-1] 中定义。
和
[MQTT-3.1.2-4] | If CleanSession is set to 0, the Server MUST resume
communications with the Client based on state from the current Session
(as identified by the Client identifier). If there is no Session
associated with the Client identifier the Server MUST create a new
Session. The Client and Server MUST store the Session after the Client
and Server are disconnected.
但我再也见不到RX3了
当然,同样的规则也适用于 TX3?服务器在 pubcomp'd 我时取得所有权,并且必须将它添加到我们当时共享的开放会话中,因此它知道我是 QoS2 订阅者,该消息尚未发送给它,方式与666,因此 - 按照我的逻辑 - 我必须收到 RX3 re-send 以及 666?
除了 mosquitto 没有做到 re-send T[3] 之外,唯一对我有意义的是对这个词的进一步解释:
[MQTT-3.1.2-5] | After the disconnection of a Session that had
CleanSession set to 0, the Server MUST store further QoS 1 and QoS 2
messages that match any subscriptions that the client had at the time
of disconnection as part of the Session state.
我看到 666 是如何“进一步”的,因为它发生在中断之后。我还看到 3 在休息之前,因此不是“进一步”...... ,因为我曾经并且仍然是同一会话中该主题的订阅者,它知道它没有向我发送实例,无论它来自哪里!
如果这是正确的并且 moz 中没有错误,那么这意味着在物理上不可能在同一设备上使用 RX 和 TX 编写 out-and-back QoS2 测试程序......或更准确地说同一个会话。作为我的示例(以及我的许多 wireshark 日志)最终证明消息 3 永远不会在重新连接时发送。因此,我的测试仪“错过”了一个交易对并声称 QoS2 失败。具有讽刺意味的是,如果我在两个单独的程序中有 TX 和 RX,RX-only - 没有崩溃 - 肯定会收到它并保持“in-step”并声称连续 QoS2 成功?我还没有测试过这个,我会等着看我是否会先在这里得到一个有用的答案,以确保我没有遗漏任何东西(除了 RX[3] :))
但这似乎自相矛盾
The Session state in the Server consists of:
· The existence of a Session, even if the rest of the Session
state is empty.
· The Client’s subscriptions.
· QoS 1 and QoS 2 messages which have been sent to the Client,
but have not been completely acknowledged.
· QoS 1 and QoS 2 messages pending transmission to the Client.
· QoS 2 messages which have been received from the Client, but
have not been completely acknowledged.
因为我看不出有什么办法可以证明我丢失的 RX3 不是“等待传输到客户端的 QoS 1 和 QoS 2 消息”。无论是“进一步”还是其他!
最后,在同一点上,当 moz CONNACKs 与会话集时,这到底意味着什么?我的意思是它认为它有一些存储的会话需要重播,在这种情况下,我接下来看到的应该是传入的 pubrels 等。当 session==true 但服务器没有发送任何内容时,这是什么意思?是不是告诉我它认为我应该有一些需要重播的存储会话数据?如果是这样,为什么?我已经知道了,因为 - 就像一个 god boy-我已经存储了会话状态,我会在重新连接时重播,所以我不需要被告知!对我来说, session==true 应该只意味着一件事:“等待一些传入的重播请求”......如果它再次出现,那么我看到 session==true 并且在大多数情况下没有任何传入。如果没有,那么我又很困惑,我很乐意承认这是最有可能的答案......但是:
在上面的例子中,mosquitto 是否应该在“脏会话”重新连接时发送 TX[3]?如果不是,为什么不呢?
解决方案是将广告持久化为 mosquitto.conf 文件
谁能解释为什么此 MQTT QoS 消息从未发送过? 答案:需要在 conf 文件中设置 persistent true,然后出现确切的预期行为。
更多详情
我有一个简单的问题(尽管起始条件很复杂)。如果答案是“是”,那么 mosquitto 中就有一个错误,如果是“否”,那么它是对规范的一个非常微妙的解释,我(我怀疑很多其他人)没有完全理解。在第二种更有可能的情况下,这意味着不可能在单个设备上使用 sub 和 pub 对同一主题编写完全符合 QoS2 的“序列测试器”。
设置 订阅 T @ QoS2 并每次都启动 clean==false 的代码。每 1 秒发布一个整数值递增的 T,这样在正常操作过程中,事件顺序为:
- 客户端->服务器TX 1
- 服务器酒吧 1
- RX 1
- TX 2
- 服务器酒吧 2
- RX 2
等等
然后我故意随机中断与服务器的连接,以测试我的恢复程序。
重新启动时,我的测试客户端正确识别失败的 TX,因为它已存储状态,例如TX3 失败并重新发送,当然还有 mosquitto re-acks ...无论术语如何,如果中断在 TX 4 路的中间,我的代码恢复正确,如果它在 RX 4 的中间-way 然后 mosquitto 立即“恢复”它自己的失败 TX,一切都按预期进行。我从来没有得到 N 的任何“遗漏”值,并且我声明我的代码完全有效。那么我的问题是什么?
连接中断/重启行为异常 考虑 TX 和服务器 pub 之间的连接何时中断(我的下一个 RX 是什么),即 TX3 完全成功 PUB/REC/REL/COMP,如果没有中断,我将打印“RX 3”。接下来我使用 mqtt-spy 来发布 T[666]。然后我重新启动我的客户端。我得到的第一件事是来自服务器的 666 消息,这对我来说听起来很正确并且似乎同意:
当服务器获得传入应用程序消息的所有权时,它必须将其添加到具有匹配订阅的那些客户端的会话状态中。匹配规则在第 4.7 节 [MQTT-4.5.0-1] 中定义。 和
[MQTT-3.1.2-4] | If CleanSession is set to 0, the Server MUST resume communications with the Client based on state from the current Session (as identified by the Client identifier). If there is no Session associated with the Client identifier the Server MUST create a new Session. The Client and Server MUST store the Session after the Client and Server are disconnected.
但我再也见不到RX3了
当然,同样的规则也适用于 TX3?服务器在 pubcomp'd 我时取得所有权,并且必须将它添加到我们当时共享的开放会话中,因此它知道我是 QoS2 订阅者,该消息尚未发送给它,方式与666,因此 - 按照我的逻辑 - 我必须收到 RX3 re-send 以及 666?
除了 mosquitto 没有做到 re-send T[3] 之外,唯一对我有意义的是对这个词的进一步解释:
[MQTT-3.1.2-5] | After the disconnection of a Session that had CleanSession set to 0, the Server MUST store further QoS 1 and QoS 2 messages that match any subscriptions that the client had at the time of disconnection as part of the Session state.
我看到 666 是如何“进一步”的,因为它发生在中断之后。我还看到 3 在休息之前,因此不是“进一步”...... ,因为我曾经并且仍然是同一会话中该主题的订阅者,它知道它没有向我发送实例,无论它来自哪里!
如果这是正确的并且 moz 中没有错误,那么这意味着在物理上不可能在同一设备上使用 RX 和 TX 编写 out-and-back QoS2 测试程序......或更准确地说同一个会话。作为我的示例(以及我的许多 wireshark 日志)最终证明消息 3 永远不会在重新连接时发送。因此,我的测试仪“错过”了一个交易对并声称 QoS2 失败。具有讽刺意味的是,如果我在两个单独的程序中有 TX 和 RX,RX-only - 没有崩溃 - 肯定会收到它并保持“in-step”并声称连续 QoS2 成功?我还没有测试过这个,我会等着看我是否会先在这里得到一个有用的答案,以确保我没有遗漏任何东西(除了 RX[3] :))
但这似乎自相矛盾
The Session state in the Server consists of:
· The existence of a Session, even if the rest of the Session state is empty.
· The Client’s subscriptions.
· QoS 1 and QoS 2 messages which have been sent to the Client, but have not been completely acknowledged.
· QoS 1 and QoS 2 messages pending transmission to the Client.
· QoS 2 messages which have been received from the Client, but have not been completely acknowledged.
因为我看不出有什么办法可以证明我丢失的 RX3 不是“等待传输到客户端的 QoS 1 和 QoS 2 消息”。无论是“进一步”还是其他!
最后,在同一点上,当 moz CONNACKs 与会话集时,这到底意味着什么?我的意思是它认为它有一些存储的会话需要重播,在这种情况下,我接下来看到的应该是传入的 pubrels 等。当 session==true 但服务器没有发送任何内容时,这是什么意思?是不是告诉我它认为我应该有一些需要重播的存储会话数据?如果是这样,为什么?我已经知道了,因为 - 就像一个 god boy-我已经存储了会话状态,我会在重新连接时重播,所以我不需要被告知!对我来说, session==true 应该只意味着一件事:“等待一些传入的重播请求”......如果它再次出现,那么我看到 session==true 并且在大多数情况下没有任何传入。如果没有,那么我又很困惑,我很乐意承认这是最有可能的答案......但是:
在上面的例子中,mosquitto 是否应该在“脏会话”重新连接时发送 TX[3]?如果不是,为什么不呢?
解决方案是将广告持久化为 mosquitto.conf 文件