请选择 进入手机版 | 继续访问电脑版

默认
发表评论 12
完全自已开发的IM该如何设计“失败重试”机制?
5金币
团队自己开发的IM软件,打算自己设计协议,现在在wifi和4G情况下,消息到达率都很理想,但是在电梯,地铁等等网络环境较差的情况下很容易发送失败。

在TCP连接的处理中已经定义了断线自动重连的机制,上层也定义了自动重发,但是这样容易造成消息重复(服务器不大可能把新来的消息id和过去所有消息id来对比判断重复吧?)。那么,如何设计好这个失败重试的机制,使得客户端能做好失败重试,服务器有能够排除这种重复消息,但是排重处理不太复杂?

最佳答案

查看完整内容

做法一: 上层做重发,例如可以失败后第一次10秒重发,再失败30秒,再失败60秒,再失败提示用户。 做法二: 失败直接提示用户,让用户主动去重发。 无论哪种做法,只是产品设计的不同,都需要做去重处理,每个客户端要维护一个自增长id,服务器只保存收到的最后一条消息的id,客户端再来消息后,只需要判断来自客户端的id是否大于服务器保存的这个就可以。
标签:即时通讯
上一篇:为什么QQ用的是UDP协议而不是TCP协议?下一篇:socket出现少量close_wait后所有连接都不能发消息的问题

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

推荐方案
评论 12
做法一: 上层做重发,例如可以失败后第一次10秒重发,再失败30秒,再失败60秒,再失败提示用户。
做法二: 失败直接提示用户,让用户主动去重发。
无论哪种做法,只是产品设计的不同,都需要做去重处理,每个客户端要维护一个自增长id,服务器只保存收到的最后一条消息的id,客户端再来消息后,只需要判断来自客户端的id是否大于服务器保存的这个就可以。

评分

1

查看评分

这种一般倾向于不解决,这种重复的几率很小,就算重复了在聊天场景下一般也没什么问题。非得用技术手段,只存最近一条消息的id是可以的,当然也可以算最近发送消息的哈希值,如果客户端不能保证id不变的话。
PS:现在即时通讯云市场辣么成熟都成红海了,还几乎免费,为啥还要养团队自己搞?
引用:harrytang 发表于 2016-05-03 21:49
这种一般倾向于不解决,这种重复的几率很小,就算重复了在聊天场景下一般也没什么问题。非得用技术手段,只 ...

成熟是别人的,不可控,不可靠。
一个用户,给另一个用户,发任何信息,都会保存一个本地自增ID。发信息时,把该ID也发过去。

对方检查该ID是否连续就可以保证不乱序,不丢失。
每一个消息要有ID,然后消息有回执,就不会发生重发的情况了。

TCP本身是有重发,但是网络总是很复杂的,需要再加重发来提高消息成功率。
后台架设接入网关,接入网关负责每一个用户的接入session,在这一层做网络数据包的过滤,可以叫做接入层协议,协议内带有package id,如果这个package id对于这个用户已经是处理过,就直接丢弃,否则解包得到具体的业务协议,然后把业务协议发送到对应的业务处理服务器。

id采用整型,由客户端决定初始值,自增。
不管传输层是TCP还是UDP协议,因为文本消息按现在主流IM的设计思路,都是ClineA-Sservr-ClinetB这种转发方式实现,所以应答机制是必不可少的,相应的失败重试机制也就可以实现了(无论网络环境多复杂,只要守住最后一道关口:只有当收到应答包才认为对方已收到消息)。

但对于你所说的重传可能存在重复的情况,这是可能存在的,因为极端情况下应答包也是可能会丢失的,如果不做重传去重处理,那么重传势必导致消息重复。MobileIMSDK 是这么做的:因为UDP存在乱序的风险,所以不存在自增ID这种方法,不过可以把最近一段时间内(MobileIMSDK默认把最近5分钟内,不一定非得5分钟,只要保证这个时间大于正常的重传时间极值范围就可以了,长一点问题不大)收到的消息id给缓存了起来,这样就可以在收到重传包时进行去复判断了。不过,为了减轻服务器压力,不建议将这个缓存id保存到服务端(直接在接收端实现一个简单的队列不就行了吗),这样既可以简化server的设计、也可以防止服务性能瓶颈的发生(因为IM系统的瓶颈几乎只发生在服务端,所以server的设计一定要尽可能地简化,这样便于以后的性能扩展和优化)。
签名: 《融云技术分享:融云安卓端IM产品的网络链路保活技术实践》http://www.52im.net/thread-2744-1-1.html
很棒,非常感谢,很清晰~
引用:JackJiang 发表于 2016-05-03 22:09
不管传输层是TCP还是UDP协议,因为文本消息按现在主流IM的设计思路,都是ClineA-Sservr-ClinetB这种转发方 ...

大神请教下,im服务的消息经过网关再到客户端,客户端没收到消息时重试。请问这个重试加到网关去做还是im去做比较合适。
引用:年糕 发表于 2018-11-20 16:18
大神请教下,im服务的消息经过网关再到客户端,客户端没收到消息时重试。请问这个重试加到网关去做还是im ...

最简单的办法是让客户端自已来决定,即在一定的超时时间内,如果没有收到对方的应答包,就可以再次重传。
这样的逻辑下,就不会把服务端的逻辑搞复杂。因为服务端只会越做越复杂,保持服务端逻辑的简洁性,服务端以后的升级和扩展就越来越好做。
签名: 《融云技术分享:融云安卓端IM产品的网络链路保活技术实践》http://www.52im.net/thread-2744-1-1.html
引用:JackJiang 发表于 2018-11-20 16:24
最简单的办法是让客户端自已来决定,即在一定的超时时间内,如果没有收到对方的应答包,就可以再次重传。 ...

感谢回复可能是我没表述清楚,是这样子。服务端下发消息,一条消息从im服务端 ,经过网关服务器,再到客户端。客户端没接收到这条消息的时候是不知道有这条消息存在的就像我给你发消息,你没收到的时候是不知道我给你发了一条消息。所以这个时候就需要im服务或者网关这边没收到客户端的应达包去重试。这个重试做在im服务好还是做到网关服务去比较好。
引用:年糕 发表于 2018-11-20 17:32
感谢回复可能是我没表述清楚,是这样子。服务端下发消息,一条消息从im服务端 ,经过网关服务器,再 ...

肯定是im服务端了,否则要是重试了还送不到,那网关不得要实现具体的离线业务代码了,网关肯定不能放进这些具体的业务逻辑,否则重用性、独立性就差
签名: 《融云技术分享:融云安卓端IM产品的网络链路保活技术实践》http://www.52im.net/thread-2744-1-1.html
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部