xhs*_*ier 10 message xmpp ejabberd xmppframework
我正在使用ejabberd服务器和ios xmppframework.有两个客户,A和B.
- 当A和B在线时,A可以成功向B发送消息.
- 如果B离线,B可以在B再次联机时收到消息.
- 但是当B突然/意外地丢失连接时,例如手动关闭wi-fi,A发送的消息就会丢失.B永远不会收到此消息.
我想原因是B突然失去连接,服务器仍然认为B在线.因此,离线消息在这种情况下可以正常工作.
所以我的问题是如何确保B发送的消息将被B接收?确保没有消息丢失.
Chr*_*her 11
我花了最后一周试图在我的XMPPFramework和eJabberd消息应用程序中追踪丢失的消息.以下是我完成的所有步骤,以确保邮件传递以及每个步骤的效果.
Mod_offline
在ejabberd.yml配置文件中,请确保您在访问规则中具有此功能:
max_user_offline_messages:
admin: 5000
all: 100
Run Code Online (Sandbox Code Playgroud)
这在模块部分:
mod_offline:
access_max_user_messages: max_user_offline_messages
Run Code Online (Sandbox Code Playgroud)
当服务器知道邮件的收件人处于脱机状态时,他们将存储它并在重新连接时传递它.
平(XEP-199)
xmppPing = XMPPPing()
xmppPing.respondsToQueries = true
xmppPing.activate(xmppStream)
xmppAutoPing = XMPPAutoPing()
xmppAutoPing.pingInterval = 2 * 60
xmppAutoPing.pingTimeout = 10.0
xmppAutoPing.activate(xmppStream)
Run Code Online (Sandbox Code Playgroud)
Ping的作用类似于心跳,因此服务器知道用户何时处于脱机状态但未正常断开连接.最好不要通过断开连接来依赖它,applicationDidEnterBackground但是当客户端失去连接或者流因为未知原因而断开连接时,有一个时间窗口,客户端处于脱机状态,但服务器还不知道它,因为ping不是预计到未来的某个时间.在这种情况下,邮件不会传递,也不会存储以供离线传递.
流管理(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)
Run Code Online (Sandbox Code Playgroud)
然后在 xmppStreamDidAuthenticate
xmppStreamManagement.enableStreamManagementWithResumption(true, maxTimeout: 100)
Run Code Online (Sandbox Code Playgroud)
就快到了.最后一步是返回ejabberd.yml并将此行添加到下面的监听端口部分access: c2s:
resend_on_timeout: true
Run Code Online (Sandbox Code Playgroud)
流管理在每次消息传递后添加req/akn握手.它本身不会对服务器端产生任何影响,除非resend_on_timeout设置(默认情况下不是eJabberd).
当收到的消息的确认没有到达服务器并且它决定保留它以进行离线传送时,需要考虑最终边缘情况.客户端下次登录时,可能会收到重复的消息.为了处理这个问题,我们为XMPPStreamManager设置了该委托.实现xmppStreamManagement getIsHandled:和如果消息有聊天正文设置isHandledPtr为false.构造出站消息时,添加具有唯一ID的xmppElement:
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)
Run Code Online (Sandbox Code Playgroud)
然后,当您收到消息时,通知流管理器该消息已被处理 xmppStreamManager.markHandledStanzaId(message.from().resource)
此最后一步的目的是建立一个唯一的标识符,您可以XMPPMessageArchivingCoreDataStorage在显示之前添加该标识符并检查重复项.
我想原因是B突然失去连接,服务器仍然认为B在线.因此,离线消息在这种情况下可以正常工作
是的,你是绝对正确的,这是众所周知的TCP连接限制.
您的问题有两种解决方法
1服务器端
我可以看到你使用ejabbed作为XMPP服务器你可以实现 mod_ping,启用此模块将启用服务器端心跳[ping],如果连接到服务器[ejabbed]连接断开将尝试发送心跳到连接并将检测连接是服务器和客户端之间丢失.使用这种方法有一个缺点,模块mod_ping具有名为ping_interval的属性,该属性表示将心跳发送到连接的客户端的频率,这里下限是32秒,ejabbed忽略32以下的任何值,意味着你有32秒的黑色窗口,其中有消息如果用户在线播种,可能会丢失
2客户端
从客户端,您可以实现消息传递收据 机制.当接收者用户收到消息时,每个聊天消息向接收者用户发送一个收据,发回该收据ID.这样,您就可以检测到您的消息实际上已传递给接收方.如果您在特定时间间隔内未收到此类确认,则可以在本地(在移动电话上)将用户显示为脱机,将本地用户的任何其他消息作为脱机消息[在SQLLight数据库中]存储,并等待离线状态节用户,一旦您收到离线状态节,就意味着服务器最终检测到该用户的连接丢失并使用户状态为离线,现在您可以将所有消息发送给该用户,该用户将再次作为脱机消息存储在服务器上这是避免黑窗的最佳方法.
结束语 您可以使用方法2并以这种方式设计客户端,也可以使用方法1和方法2来最小化服务器断开的连接缩减时间.
| 归档时间: |
|
| 查看次数: |
4201 次 |
| 最近记录: |