默认
发表评论 10
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
求教自研IM服务端,在客户端在线状态不准确情况下如何保证消息的送达?
阅读(40975) | 评论(10 收藏 淘帖1
现在遇到一个问题,我们心跳是隔30秒发送一次,连续3次发送失败认为是离线,这个时候有消息会走ios原生推送,但是有时候客户端app放到后台后ios系统把app杀死了,服务端也检测不到,不会马上把状态改成offline这个时候有1分30秒的状态误判,收到消息后还是会走了通道去发,但是真正这个链接已经不能用了,客户端是收不到消息的,正确做法应该要走原生推送给客户端发消息。

我们的需求是假设a给b发送消息,一直发送的情况下,假设每秒发送一条消息,消息的内容为1,2,3,4.....,假设b是在15条的时候按了home键回到后台,收到第100条的时候被系统回收,因为第101条已经不能通过消息通道正常接收了,这个时候服务器记录b的在线状态是online,没有走第三方推送或者ios原生推送,我想实现的是第101条就立刻能通过第三方推送或者ios原生推送推送到b客户端(说明一下我们服务器现在发送逻辑是先判断b的online和offline如果是online直接通道发送,如果是offline就走ios原生推送,安卓就走第三方推送)。因为ios按home键返回后台服务器是监听不到的,是没有调用链接的colse方法的,服务器认为这个链接是正常的,只有三次心跳失败才把online状态改成offline,导致这1分30秒不能及时收到消息,要等激活app后才离线拉取。
我们后来想了一个办法:就是看ios有没有被系统杀死进程前一刻调用一下链接的colse方法通知服务器,但是好像没有找到这样的方法,ios前端开发人员跟我说只有一个任务执行完后触发的方法,我们在那个方法上调用了一下链接的关闭方法,但是效果不太理想,不知道有没有更好的解决办法。

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

标签:求助 IM开发
上一篇:关于IM群消息,服务端是否应该给发送者回复ack应答?下一篇:用go写im,server的接收缓冲区跟发送缓冲区设置多少合适?

本帖已收录至以下技术专辑

推荐方案
评论 10
你的问题:其实是你客户端跟服务端,对TCP协议的原理了解的不够导致的。

TCP连接正常建立后:包括你客户端崩溃、非正常退出、网络链路中间的任何一个环节断掉,你服务端是无法及时感知到的。

而且,像网络链路中,某个路由断开,然后又恢复的情况下,是不影响你TCP的通信的。

所以,基于种种网络复杂性,单靠TCP协议本身,是无法做到精确感知网络连接是否真的正常、或已断开。

一个主流的作法是:你应该加一个消息重传机制,也就是,当出现上面这些服务端误判对方在线,而错误的将消息以对方“在线”的逻辑发送出去时,有个补救措施。

你可以去参考一下MobileIMSDK工程 ,它里面有有完整的心跳、QoS消息送达保证机制,你可以学习借鉴一下,应该能给你灵感。
其实我的真正问题不是丢消息,这样不得不跟你说下我们的消息补偿机制了,我们现在每发送一条消息给客户端都客户端都会马上响应ack给服务器,如果服务器没有收到ack就会不断重新发送消息给客户端,因为上面链接不可用导致服务器误判b在线,但是发给b的消息都没有收到回执,就会一直发送消息给b,像上面那条101的消息会重发3次,因为没有收到客户端响应的ack触发了补偿机制,但是其实这样的消息我不想它触发消息补偿机制。这样问也不大只是浪费了服务器性能.
引用:liang156com 发表于 2020-10-15 12:26
其实我的真正问题不是丢消息,这样不得不跟你说下我们的消息补偿机制了,我们现在每发送一条消息给客户端都 ...

这种情况,其实没有其它更好的办法
引用:JackJiang 发表于 2020-10-15 12:40
这种情况,其实没有其它更好的办法

嗯嗯,好的
避免不了,由客户端主动拉取新消息就好
签名: 。。。。。。
我觉得吧,还得在“如何准确的知晓客户端状态” 上,做些修改。
1 如果用 netty 的话,有默认的心跳机制,也可以自己实现。 如果得不到心跳的话,就认为客户端已离线。发消息的时候,要先判断这个在线状态。 ios 中切换到后台的话,没被杀死可以推送到,杀死的话,通过心跳机制可以感知。

2 心跳机制有个时间间隔,如果刚好在时间间隔内,客户端掉线,服务端还未正确感知到,那么推送的时候会返回连接已关闭,这时手动修改客户端状态为已离线就好。
引用:magicnana999 发表于 2020-11-12 10:51
我觉得吧,还得在“如何准确的知晓客户端状态” 上,做些修改。
1 如果用 netty 的话,有默认的心跳机制, ...

“ 心跳机制有个时间间隔,如果刚好在时间间隔内,客户端掉线,服务端还未正确感知到,那么推送的时候会返回连接已关闭,这时手动修改客户端状态为已离线就好。”:
》这个怕是不容易办到,因为现在像netty这种服务端框架,数据发送都是异步送出,连接是否已关闭是不好直接获取的。而且对于非正常关闭的半开连接,服务端也是不知道的,它只当网络有问题,进入TCP的重传队列了,不会立即返回结果的。
刚翻了下netty 代码(java),发送消息的时候,可以注册一个监听,当最终结果到达的时候,可以做后续的处理。关于半开半闭的连接,同理如此。

1605160272646.jpg (141.29 KB, 下载次数: 1663)

1605160272646.jpg
引用:magicnana999 发表于 2020-11-12 14:21
刚翻了下netty 代码(java),发送消息的时候,可以注册一个监听,当最终结果到达的时候,可以做后续的处理 ...

对于netty来说,主要还是依赖于超时机制,但超时的话那就是多少秒之后的事情了,时间差还是免不了.
你看Netty源码的话,不用打开开发工具,可以直接用我编译的这个在线版本,网页里直接看:http://docs.52im.net/extend/docs/src/netty4_1/
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部