弱网络环境下手游断线重连和协议重发方案

在手游开发中,弱网络的问题主要集中在网络切换、网络异常、网络抖动等问题上,并且弱网络会造成“丢包”(注:这里指的丢包不是指传输层的丢包,而是指客户端未收到服务器的包)的情况,特别是一些关键请求(比如购买)在弱网络下重复发送,会导致多次扣费的问题,因此,需要客户端设计比较好的网络断线重连机制以及协议重发方案,来解决这一问题。

以下具体说一下自己在项目遇到的问题和解决办法

Question

在弱网络环境下,协议的请求和应答都有可能因为网络的原因造成不匹配,下面列出几种情况,如下图。尤其是第四种情况,服务器多次收到客户端的同一请求,并且成功处理,如果是购买或者影响到玩家收益的相关协议,会造成多次扣除的问题。

 

        

1.正常情况                 2.断线后协议发送不出去

 

        

3.协议发送出去后断线        4.协议发送出去后断线,再次连上并重复发包

 

Solutions

1、重复请求的处理

在我们自己定义的协议头里除了带上请求的协议ID以外,再加上一个序列号,让服务器识别重复请求。

序列号由客户端产生,除了重发协议的请求序列号和上次一样之外,保证每条协议请求的序列号都是不一样的,我现在的做法是:初始随机产生,后面加1。

 

服务器对应的处理流程

 

2、断线重连

当检测到连接断开后,客户端并不是立马弹出提示让用户选择重连,而是默默的记录下来,当玩家主动操作发生协议请求的时候弹出,这样处理避免频繁的弹框打扰玩家,从而提升玩家的体验。

重新连接成功后,应服务器的要求,客户端会发送一次重登请求,以激活玩家的在线状态,最后重发送客户端因断连后未发出请求数据。

3、心跳超时

心跳包用于检测客户端和服务器之间的连接状态,客户端启动定时器不断发送心跳包,如果在超时时间内未收到服务器的心跳回包,客户端即认为心跳超时。这时,客户端也是默默记录下一个状态标识为心跳超时,并且停止定时器;当玩家主动操作发生协议请求的时候,客户端静默发送一次重登请求,成功收到重登回包后,客户端重置心跳超时状态,并重启心跳定时器。

4、协议超时

每条协议请求都有自己的一个定时器,若超时时间内成功收到服务器的应答,则停止定时器,并从协议缓存中移除本条请求数据;若未收到应答,则停止定时器,弹出提示框告知玩家协议超时,让玩家选择是否重试(重试即重发上次请求数据,取消则从协议缓存中移除该请求数据)。

5、模态菊花

为了保证一些关键协议的请求和应答是串行处理的,同时也是为了避免玩家频繁的操作带来一些不必要的请求,客户端在发生协议请求的时候,蒙上模态菊花锁定UI,等到该请求完成处理后(如收到服务器应答、客户端检测到断线、协议超时),才能去掉模态菊花,解除UI锁定。

当然,不是每条协议都需要这样做,比如心跳等。因此,底层接口需要提供参数供各个模块选择发送该请求是否需要模态。

当这样做以后,产品吐槽说这样体验很不好,随便点一下就要看到这个菊花,很不爽!于是,针对这个模态菊花也做了一个淡入的效果(它一开始就是存在的只是看不见而已),延迟越低模态菊花越不明显,从而提升玩家体验。

总结

目前,通过上述的一些办法,手机进出电梯、游戏切后台、网络切换,之后都能继续正常的体验游戏。

不足之处还望多多指教。