1

我正在使用 ejabberd 的 iOS 上构建即时通讯应用程序。我目前正在测试流管理功能,特别是在大多数情况下似乎有效的恢复。但是有一个我不明白的情况,我可以通过以下步骤复制,考虑到设置:resume_timeout:30,resend_on_timeout:if_offline

  • 一开始客户端A和客户端B是连接的,没有连接其他资源
  • 客户端 B 以不干净的方式崩溃或断开连接
  • 客户端 A 开始非常快速地发送一堆消息(10+)
  • ejabberd 为每个发送的消息向 A 发送一个 ack,以确认消息已到达服务器
  • 崩溃后大约 20 秒,B 重新连接。此时 A 收到之前发送的每条消息的错误
<message xmlns="jabber:client" from="clientB@mydomain" to="clientA@mydomain/resourceID" type="error" id="CFBF4583-209A-4453-2567-CCCC7894827E">
   <body>test</body>
   <active xmlns="http://jabber.org/protocol/chatstates" />
   <request xmlns="urn:xmpp:receipts" />
   <error code="503" type="cancel">
       <service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
   </error>
</message>

我尝试使用 ejabberd 16.01。

这发生在 80% 的时间;有时 A 发送的消息会在 30 秒内重新连接时正确传递给 B。

我的问题是:

  • 这种行为正确吗?如果已经收到消息的确认,我希望不会向客户端 A 退回任何错误。
  • 由于resend_on_timeout设置为if_offline并且没有连接其他资源,我希望完全没有错误。我对么?
4

2 回答 2

2
  • 流管理确认仅表明您的服务器已收到消息。这并不意味着消息已被处理或传递到指定地址。即使它已发送到该地址,该设备仍然可以返回该节的错误。
  • 这实际上只是在黑暗中刺伤,但是在浏览了 ejabberd 代码之后,可能会发生以下情况:

    1. clientB@mydomain/ResourceB断开他们的连接,现在有一个会话等待使用ResourceB.
    2. 客户端 B 重新连接,不恢复(因为它崩溃并丢失了状态)。
    3. 客户端 B 再次绑定资源ResourceB
    4. 现在服务器必须终止等待恢复的睡眠会话,因为客户端 B 请求了相同的资源。
    5. 服务器检查是否有其他会话,因为它设置为if_offline
    6. 服务器看到有一个会话(新会话),因此选择退回而不是重新发送。

    所以我的理论是,if_offline仅在需要处理未确认消息队列时检查是否有其他会话,而不是在最初收到消息时检查。

于 2016-02-02T13:47:18.177 回答
1

@xnyhps 的回答是正确的,我为下一个 ejabberd 版本修复了这个特殊的极端情况。但是,@xnyhps 也有其他极端情况是正确的,因此如果您想要可靠的消息传递,您应该使用 XEP-0313。XEP-0198 的主要特征是会话恢复。

于 2016-02-06T23:17:07.797 回答