当客户端连接突然丢失时,xmpp消息也会丢失 [英] xmpp messages are lost when client connection lost suddently

查看:446
本文介绍了当客户端连接突然丢失时,xmpp消息也会丢失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ejabberd服务器和ios xmppframework. 有两个客户A和B.

I am using ejabberd server and ios xmppframework. there are two clients, A and B.

  1. A和B联机时,A可以成功向B发送消息.
  2. 如果B离线,则B可以在再次在线时收到消息.
  3. 但是,当B突然/意外断开连接时,例如手动关闭wi-fi,A发出的消息就会丢失. B永远不会 收到此消息.
  1. When A and B are online, A can send message to B successfully.
  2. If B is offline, B can receive the message when B is online again.
  3. But when B is suddenly/unexpectedly lost connection, such as manually close wi-fi, the message sent by A is lost. B will never receive this message.

我想原因是B突然失去了连接,服务器仍然认为B处于在线状态.因此,脱机消息确实在这种情况下起作用.

I guess the reason is that B lost connection suddenly and the server still think B is online. Thus the offline message does work under this condition.

所以我的问题是如何确保A发送的消息将被B接收?为了确保没有消息丢失.

So my question is how to ensure the message that sent by A will be received by B? To ensure there is no messages lost.

推荐答案

上周,我试图在XMPPFramework和eJabberd消息传递应用程序中查找丢失的消息.这是我为保证消息传递所经历的全部步骤,以及每个步骤的作用.

I've spent the last week trying to track down missing messages in my XMPPFramework and eJabberd messaging app. Here are the full steps I went through to guarantee message delivery and what the effects of each step are.

Mod_offline

在ejabberd.yml配置文件中,确保您在访问规则中具有此名称:

In the ejabberd.yml config file ensure that you have this in the access rules:

max_user_offline_messages:
  admin: 5000
  all: 100

,并且在模块"部分:

mod_offline:
  access_max_user_messages: max_user_offline_messages

当服务器知道邮件的收件人处于脱机状态时,他们将存储该邮件,并在重新连接时将其传递.

When the server knows the recipient of a message is offline they will store it and deliver it when they re-connect.

Ping(XEP-199)

xmppPing = XMPPPing()
xmppPing.respondsToQueries = true
xmppPing.activate(xmppStream)

xmppAutoPing = XMPPAutoPing()
xmppAutoPing.pingInterval = 2 * 60
xmppAutoPing.pingTimeout = 10.0
xmppAutoPing.activate(xmppStream)

Ping就像心跳一样,因此服务器可以知道用户何时处于脱机状态,但无法正常断开连接.最好不要通过断开applicationDidEnterBackground的连接来依赖于此,但是当客户端由于未知原因而断开连接或流断开连接时,客户端会在一段时间内处于脱机状态,但服务器尚不知道该状态,因为直到将来的某个时候才预期会执行ping操作.在这种情况下,邮件不会传递,也不会存储为脱机传递.

Ping acts like a heartbeat so the server knows when the user is offline but didn't disconnect normally. It's a good idea to not rely on this by disconnecting on applicationDidEnterBackground but when the client looses connectivity or the stream disconnects for unknown reasons there is a window of time where a client is offline but the server doesn't know it yet because the ping wasn't expected until sometime in the future. In this scenario the message isn't delivered and isn't stored for offline delivery.

流管理(XEP-198)

xmppStreamManagement = XMPPStreamManagement(storage: XMPPStreamManagementMemoryStorage(), dispatchQueue: dispatch_get_main_queue())
xmppStreamManagement.autoResume = true
xmppStreamManagement.addDelegate(self, delegateQueue: dispatch_get_main_queue())
xmppStreamManagement.activate(xmppStream)

,然后在xmppStreamDidAuthenticate

xmppStreamManagement.enableStreamManagementWithResumption(true, maxTimeout: 100)

在那附近.最后一步是返回ejabberd.yml并将此行添加到access: c2s下的侦听端口部分:

Nearly there. The final step is to go back to the ejabberd.yml and add this line to the listening ports section underneath access: c2s:

resend_on_timeout: true

流管理在每次传递消息后添加请求/确认握手.它本身不会对服务器端产生任何影响,除非已设置resend_on_timeout(在eJabberd中默认情况下未设置).

Stream Management adds req/akn handshakes after each message delivery. On it's own it won't have any effect on the server side unless that resend_on_timeout is set (which it isn't by default on eJabberd).

当接收到的消息的确认未到达服务器并且它决定将其保留以供脱机传递时,需要考虑最终的边缘情况.客户端下次登录时,他们很可能会收到重复的消息.为了处理此问题,我们为XMPPStreamManager设置了该委托.实现xmppStreamManagement getIsHandled:,如果消息具有聊天正文,则将isHandledPtr设置为false.构造出站邮件时,请添加具有唯一ID的xmppElement:

There is a final edge case which needs to be considered when the acknowledgement of a received message doesn't get to the server and it decides to hold it for offline delivery. The next time the client logs in they are likely to get a duplicate message. To handle this we set that delegate for the XMPPStreamManager. Implement the xmppStreamManagement getIsHandled: and if the message has a chat body set the isHandledPtr to false. When you construct an outbound message add an xmppElement with a unique id:

let xmppMessage = XMPPMessage(type: "chat", to: partnerJID)
let xmppElement = DDXMLElement(name: "message")
xmppElement.addAttributeWithName("id", stringValue: xmppStream.generateUUID())
xmppElement.addAttributeWithName("type", stringValue: "chat")
xmppElement.addAttributeWithName("to", stringValue: partnerJID.bare())
xmppMessage.addBody(message)
xmppMessage.addChild(xmppElement)
xmppMessage.addReceiptRequest()
xmppStream.sendElement(xmppMessage)

然后,当您收到一条消息时,通知流管理器该消息已由xmppStreamManager.markHandledStanzaId(message.from().resource)

Then when you receive a message, inform the stream manager that the message has been handled with xmppStreamManager.markHandledStanzaId(message.from().resource)

此最后一步的目的是建立一个唯一的标识符,您可以将其添加到XMPPMessageArchivingCoreDataStorage并在显示之前检查重复项.

The purpose of this final step is to establish a unique identifier that you can add to the XMPPMessageArchivingCoreDataStorage and check for duplicates before displaying.

这篇关于当客户端连接突然丢失时,xmpp消息也会丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆