ejabberd 中流管理的奇怪错误
Strange errors with stream management in ejabberd
我正在 iOS 上构建一个使用 ejabberd 的即时通讯应用程序。我目前正在测试流管理功能,尤其是在大多数情况下似乎都有效的恢复功能。但是有一种情况我不明白,我可以通过以下步骤进行复制,同时考虑到设置: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
并且没有连接其他资源,我希望不会出现任何错误。我说得对吗?
- Stream Management acks仅表示消息已被您的服务器接收。这并不意味着邮件已被处理或发送到指定地址。即使它被发送到地址,那么该设备仍然可以 return 节错误。
这实际上只是盲目尝试,但在浏览了 ejabberd 代码后,可能会发生以下情况:
clientB@mydomain/ResourceB
断开连接,现在有一个会话正在等待使用 ResourceB
. 恢复
- 客户端 B 重新连接,但未恢复(因为它崩溃并丢失了状态)。
- 客户端 B 再次绑定资源
ResourceB
。
- 现在服务器必须终止正在等待恢复的休眠会话,因为客户端 B 请求了相同的资源。
- 服务器检查是否有其他会话,因为设置为
if_offline
。
- 服务器发现有一个会话(新会话),因此选择退回而不是重新发送。
所以我的理论是 if_offline
只在需要处理未确认消息队列时检查是否还有其他会话,而不是在最初收到消息时检查。
@xnyhps 的回答是正确的,我 fixed 下一个 ejabberd 版本的这个特殊情况。然而,@xnyhps 也是正确的,还有其他极端情况,所以如果你想要可靠的消息传递,你应该使用 XEP-0313。 XEP-0198的主要特点是会话恢复。
我正在 iOS 上构建一个使用 ejabberd 的即时通讯应用程序。我目前正在测试流管理功能,尤其是在大多数情况下似乎都有效的恢复功能。但是有一种情况我不明白,我可以通过以下步骤进行复制,同时考虑到设置: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
并且没有连接其他资源,我希望不会出现任何错误。我说得对吗?
- Stream Management acks仅表示消息已被您的服务器接收。这并不意味着邮件已被处理或发送到指定地址。即使它被发送到地址,那么该设备仍然可以 return 节错误。
这实际上只是盲目尝试,但在浏览了 ejabberd 代码后,可能会发生以下情况:
clientB@mydomain/ResourceB
断开连接,现在有一个会话正在等待使用ResourceB
. 恢复
- 客户端 B 重新连接,但未恢复(因为它崩溃并丢失了状态)。
- 客户端 B 再次绑定资源
ResourceB
。 - 现在服务器必须终止正在等待恢复的休眠会话,因为客户端 B 请求了相同的资源。
- 服务器检查是否有其他会话,因为设置为
if_offline
。 - 服务器发现有一个会话(新会话),因此选择退回而不是重新发送。
所以我的理论是
if_offline
只在需要处理未确认消息队列时检查是否还有其他会话,而不是在最初收到消息时检查。
@xnyhps 的回答是正确的,我 fixed 下一个 ejabberd 版本的这个特殊情况。然而,@xnyhps 也是正确的,还有其他极端情况,所以如果你想要可靠的消息传递,你应该使用 XEP-0313。 XEP-0198的主要特点是会话恢复。