【高阶】弱网络下的游戏服务器设计

发表于2015-04-30
评论0 3.4k浏览

1、背景

随着手游市场的到来,越来越多的手机游戏通过移动网络和游戏后台通信。移动网络相对传统有线网络存在网速低、不稳定的特点,而且目前是没有技术可以规避这个问题。因此发生在手机游戏上最常见的问题就是网络延迟高、频繁的掉线,为了提升游戏的玩家体验,目前客户端的主要做法有:

(1) 网络超时机制:当网络回包超过一定时间后,客户端不会一直等待,当做超时处理;

(2) 消息重发机制如果有消息发送,但是一直没有收到回包,会尝试重发几次;

(3) 掉线重连机制:信号不好,网络掉线导致和后台服务失去连接时,客户端会默默的在后台尝试登陆,重新和服务器建立连接。

 

服务器在这方面也会做一些优化,应对存在的频繁掉线问题:

(1) 会话保持机制:在服务器缓存玩家的会话信息,如果玩家掉线了,不马上清除会话,保留一段时间,以备下次玩家重新登陆可以复用这个会话;

(2) 登陆简化:因为存在频繁的掉线,所有登陆流程要细分,区分完整登陆和断线重连,保证断线重连每次只需要和客户端传递少量的数据,节省流量,提高断线重连的速度;

(3) TGW优化:优化TGW,保证一段时间内,玩家的tcp连接会较高概率的被转发到同一个服务器上,提升重用会话的机率。

以上这些优化可以很好的提升玩家的体验,但是主要是针对网速低、不稳定带来的直接影响做的努力。然而这些机制的使用,也会带来新的问题:客户端的重发机制,可能导致服务器重复的收到同一个包,从而带来一些逻辑上的问题。

 

2、 问题说明

出现重复发包问题,主要存在下面几种场景:

(2.1) 玩家的误操作:因为延迟较高,客户端给玩家的反馈较慢,玩家以为游戏卡死,可能在客户端重发的点击某个操作,比如:购买商品,服务器收到多个请求,如果没有做特殊处理,就会处理购买同个物品多次,但实际上玩家只想购买一个,给玩家带来损失,体验也不好。http://km.oa.com/files/post_photo/597/229597/237cc9fd4b9a70da185f7436ab89d20c1421731829.png

(2.2) 网络延时:网络延时太大,客户端发送后,等待回包超时,认为消息没有发送成功,故再次尝试重发同个消息。服务可能已经收到了前一个包,并且处理了。这个时候重发的包过来,就会再处理一次,会导致一些逻辑问题,比如是战斗请求消息,如果重发,后面的消息肯定会处理不成功,那么客户端就可能认为战斗失败。http://km.oa.com/files/photos/pictures/201501/1421731735_1.png

(2.3)  网络异常断开:网络断开,会导致客户端没有收到回包,故而重发,出现和(2)一样的问题.

(2.4) 服务器异常:如果服务器的异常,没有给客户端回报,也会导致和(2)一样的问题。

(2.5)  客户端和服务器数据不一致:客户端可能因为少收了服务器的包,导致数据和服务不一致,致使玩家看到错误的信息做了错误的决定。

 

3、服务器设计

针对上面存在的问题,我们引入了下面几个机制来解决

(3.1) 基于请求-应答响应模型的消息同步机制

在CS协议中增加序列号机制:

Ø  序列号初始化

服务器在每次玩家登录时初始化全局消息的序列号(默认从0开始),并在登录完成时下发给客户端,断线重连登录序列号不重置

Ø  序列号递增

服务器在收到客户端注册的消息命令字并且携带的序列号合法时,将下行发送的序列号加一

Ø  序列号检查

客户端注册命令字上行消息中的序列号需要跟当前服务器一致,若不一致下发统一的错误码及当前最新的序列号.

Ø  序列号存档

由于断线重连可能登录到不同的Gamesvr,上一个会话的序列号需要存档,并在重连的时候恢复继续计数

对于一些关键性的消息(如购买、战斗、抽奖等),客户端同步等待服务器回包,客户端在CS协议中填写序列号,服务处理前检查序列号,处理后递增序列号,随回包协议下发给客户端;

通过序列号检查,服务器可以发现那些消息时重发消息(重发消息的序列号不变),能够知道是否已经处理过该消息,并返回序列号过期错误。

为了能更好的给玩家体验,服务可以缓存最近几条回包消息,当客户端重发消息时,根据序列号,确定是否可以直接用缓存包回给客户端,给玩家更好的体验;

 

(3.2) 客户端消息频率控制

根据不同客户端消息类型控制不同消息发送的频率,可以减少玩家的误操作,也可以减轻服务器的负载;

 

(3.3) 服务器错误处理机制

对于每一个CS请求,不管服务器是要同步或异步处理,过程中发生的任何异常,都要能够给客户端一个反馈。

这要求在服务设计时,能够有个很好的错误兜底机制,在处理请求的任何一步异常时,都能捕获到错误并处理。服务器同步处理的请求,比较简单,可以马上发现异常;对于异步处理,会涉及到和其它组件服务器的交互,之间的通信机制要加上超时机制。

我们在设计服务时,所有的异步处理逻辑,都统一放到了一个Transaction中,当发现某个异步请求一段时间没返回时,Transaction会自己触发超时,在自己的销毁函数中发现错误,给客户端回报。

(3.4) 临界资源保护

游戏中一些关键性的资源(如钻石、道具),玩家在消耗时,最好可以由客户端带当前的状态信息(如数量),这样服务器可以操作前校验,保证玩家是在看到正确的数据下作的决定。

 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引