【天天炫斗】弱网处理及断线重连方案
【天天炫斗】弱网处理及断线重连方案
--hessionhe
一背景及问题描述
天天炫斗采用的是TCP长连接方式,消息交互使用的是TDR方案,弱网问题以及断线重连的情况在手游运营中都是非常普遍的,也会相互交叉出现。天天炫斗属于比较重度的RPG手游,玩家在实际游戏过程中更容易碰到“网络差”,“掉线重登”等情况,最常见的一个场景是玩家正在酣畅淋漓的闯关副本,结果此时网络不稳定,导致玩家掉线需要重登再来打一次副本,会直接造成容忍度比较低的玩家流失,游戏口碑也会受到影响。
天天炫斗的一个副本玩法中会有多个版面,玩家只有清掉前一个版面的所有敌人后才能请求进入下个版面,服务器才会下发下个版面的敌人信息给客户端。炫斗早期没有对下行包进行管理和缓存,很容易出现玩家清完一个版面的所有敌人后请求进入下个版面时断线了导致没有收到服务器下发的回复包,所以会出现客户端重连成功了但是卡在当前版面进入不了后面的流程,体验会非常差。
针对上面出现的问题,在服务器端专门针对断线重连做了相应的优化,在服务器设置了下行包缓存机制,这样重连上来后,服务器会判断客户端是否有丢失下行包,丢失了多少包,会把所有丢失的包再push给客户端一次,保证客户端能够继续前面断线时的流程。对于玩家来说,这个重连过程是透明的,能够有效提升玩家的游戏体验。下文也主要是针对这个优化进行描述,如有疏漏之处也请各位大侠指正。
二 弱网处理
1 上行包包序
客户端维护上行包的包序,服务器会记录下最近一次客户端的上行包的包序,如果客户端上报的上行包包序小于等于记录的时,服务器判断为重复发包的行为,会做丢包处理,防止重复处理同一个包的情况,造成客户端数据异常。比如:客户端购买商品之类的消息,如果不判断重复包的话,会造成多次扣费的可能,让玩家造成经济损失。
天天炫斗的服务器端会严格校验上行包的包序,通过判断上行包的包序跟服务器记录的上次的包序大小来判断该消息是否已经处理,处理过的消息将被直接丢弃,如果客户端一直收不到消息会走断线重连的方式,到时会收到服务器在断线期间为它缓存的所有消息。
2 下行包包序
服务器维护下行包的包序,客户端同样通过判断服务器的下行包包序来做对应处理,过滤已经处理过的下行包,防止出现数值和界面异常的情况
三 断线重连
客户端会保存最近一次收到的下行包的包序,每个Player的下行包的包序由服务器维护,如果客户端需要重连登录时,需要带上这个包序给服务器。
客户端正常情况下会先连目录服务器(天天炫斗架构参考http://km.oa.com/group/1667/articles/show/199945?kmref=search),选择小区后自行选择一台gamesvrd登录,之后客户端如果断线会直连上次登录过的gamesvrd,走重连流程。
下图为客户端断线重连时,直连gamesvrd的情况。
客户端的断线重连流程如下,关键的步骤为判断客户端上报的下行包包序,以及下发缓存池中的满足条件的下行包。
过滤过旧的消息以及下发满足条件的cache消息时都不移动BeginBuf, 只需要记录下一个tempBeginBuf,整个过程移动tempBeginBuf即可,这样做是因为实际上客户端处在网络不稳定时,有一定几率会持续重连失败,等到客户端再次重连时,缓存的消息可以再次被下发,不会遗漏关键的消息。
有了缓存机制后的断线重连,对于像天天炫斗这类RPG游戏来说,游戏体验会提升很多,玩家进入单局副本如果断线了,重连之后又能收到前面断线期间丢失的包,重新继续单局后面的流程,整个过程对于玩家来说是透明的,重连过程丝滑顺畅。
三 缓存机制
消息缓存是整个机制的核心部分,在本章节先对存储结构详细介绍下,服务器端在每个player对象内开辟块专门的下行包的缓存池,CS各个消息大小差异巨大,每一个下行包都经过TDR的pack方法后再存入缓存池,以节约内存。
3.1 结构设计
整个存储结构由多个节点组成,每个节点内包含三个内容:消息序列 消息大小 打包后的消息。该存储结构可以循环使用,存储消息的开始和结束有各自的游标,BeginBuf和EndBuf,往缓存内push消息时移动EndBuf游标即可,从缓存内取出消息时只需要移动BeginBuf即可。
天天炫斗为每个player对象分配了20K的内存,通过TDR的pack后,每个消息占用内存会比较小,线上的平均能够缓存的消息大概是500个左右,足够覆盖天天炫斗的大部分断线的场景了。
3.2 缓存消息处理
所有对缓存的处理只需要调用以下三个封装的接口,三个接口的调用场景后面再做描述:
a. 从缓存中取出对应大小的内存,但是不移动BeginBuf游标
__COPY_FROM_CACHE_MSG_WITHOUT_DELETE(dest_ptr, size)
b. 取出第一个消息的内存块,并移动BeginBuf游标
__COPY_FROM_CACHE_MSG(dest_ptr, size)
c. 往缓存的消息尾部存入消息,并移动EndBuf游标
__COPY_TO_CACHE_MSG(src_ptr, size)
3.3 下行包处理
服务器对每一个下行包都调用一次CacheCSMsg(stCSMsg)接口,将消息push进缓存池内,处理流程如下图:
需要缓存的消息不能在黑名单内,比如登录登出的回复包,以及服务器踢下线的通知消息之类的消息不应该缓存。
四 天天炫斗的断线统计
天天炫斗对线上的重连情况有对应统计记录,会统计每分钟发起重连的客户端次数,以及最后成功重连的次数。拉取某个gamesvr的不同时间的统计数据如下:
五 总结
各个游戏业务都有各自的特点,比如连接方式,所使用的编解码方案等,上文主要介绍了天天炫斗服务器端对下行包的缓存逻辑及结构设计、断线重连后对缓存消息的处理逻辑、弱网的简单校验。如对文中有任何问题和建议请及时抛出,欢迎大家一起探讨。