网游P2P & CS结构
早先网游使用P2P网络拓扑在玩家之间进行交换数据通信。但P2P模型引起的高延迟在FPS游戏中无法被很好掩盖,所有玩家的延迟取决于当前玩家中延迟最烂的那个。好比木桶理论,低延迟网络好的玩家会被高延迟坏网络的玩家拖累。最终结果导致,所有玩家都不太开心了。但在局域网环境下,不会感觉到延迟带来的问题。另,游戏逻辑大部分都集中在客户端了,很难避免作弊行为。
C/S结构网游:
- C/S结构在服务器端跑所有的游戏逻辑和输入响应,客户端只需要渲染以及把自己需要一些状态同步下来,把用户输入发给服务器端,然后显示结果就可以了
- C/S结构网游最大优点就是把延迟从玩家之间最卡玩家的延迟改变为玩家和服务器连接的延迟,结果就是客户端在带宽上的要求也低了不少,因为只需要把输入发给服务器端就以及接收服务器响应就够了
- C/S结构网游虽然转移了网络延迟矛盾点,但现实网络环境一样会带来较高的网络延迟。客户端每执行一次操作,都需要等待服务器端命令,那会用户操作会造成操纵卡顿现象。如何解决呢,客户端一般采用预测和插值等方式在渲染层隐藏网络延迟
客户端预测和插值
服务器可以允许某些情况下客户端本地即时执行移动操作,这种方法可以称为客户端预测。
比如游戏中键盘控制角色行走,这个时候可以在很小的时间段(时间很短,比如1-3秒)内预测用户行动轨迹(方向+加速度,角色行走结果),这部分的命令客户端会全部发送到服务器端校验正确与否(避免瞬间转移等外挂)。但客户端预测有时也不是百分百准确,需要服务器进行纠正(所谓服务器就是上帝,The sever is the man!)。纠正结果可能就是游戏角色行走轨迹和客户端预测轨迹有所偏差,客户端可以使用插值方式(粗略来讲,就是角色在两点之间移动渲染的方式)渲染游戏角色在游戏世界中的位置转移平滑一些,避免游戏角色从一个位置瞬间拉回到另一个位置,让人有些莫名其妙。
插值,有人也称之为路径补偿,都是一回事。插值的方法会涉及到很多数学公式,线性插值、三次线性插值等,比如这篇文章所讲到的插值那些事。
小结:客户端预测,服务器端纠正,客户端采用插值方式微调。
针对交互的一群玩家,网络好坏层次不齐,游戏的一些操作效果可能需要”延迟补偿“策略进行
延迟补偿
延迟补偿是游戏服务器端执行的一种策略,处理用户命令回退到客户端发送命令的准确时间(延迟导致),根据客户端的具体情况进行修正,以牺牲游戏在伤害判定方面的真实感来弥补攻击行为等方面真实感,本质上是一种折中选择。
主要注意,延迟补偿不是发生在客户端。
关于延迟补偿的一个例子:
- 在FPS游戏中,玩家A在10.5秒时向目标对象玩家B射击并且击中,射击信息被打包发送(网络延迟100毫秒),服务器于10.6秒收到,此时玩家B可能已跑到另外一个位置。
- 若服务器仅仅基于接收时刻(10.6秒)进行判断,那么玩家B没有收到伤害,或许可能会击中玩家B后面紧跟的玩家C(100ms后玩家C完全由可能已处于玩家A的射击目标位置)
- 为了弥补由于延迟造成的问题,服务器端需要引入“延迟补偿”策略用于修正因延迟造成错乱假象
- 服务器计算执行设计命令时间,然后找出当前世界10.5秒时刻玩家信息,根据射击算法模拟得出是否命中判断,以达到尽可能精确
若游戏延迟补偿被禁用,那么就会有许多玩家抱怨自己明明打中了对方却没有造成任何伤害。。
有所得,有所失:但这对低延时玩家貌似有些不公平,移动速度快,可能已经跑到角落里并且已蹲在一个箱子后面隐藏起来时被对手击中的错觉(子弹无视掩体,玩家隔着墙被射击),确实有些不乐意。
延迟补偿,网络高延迟的玩家有利,低延迟的玩家优势可能会被降低(低延迟玩家利益受损),但对维护游戏世界的平衡还是有利的。
对时&阀值&序列
客户端和服务器需要对时,互相知道彼此延迟情况:
客户端发送一个本地时间量给服务器,服务收到包后,夹带一个服务器时间返回给客户端。当客户端收到这个包后,可以估算出包在路程上经过的时间。同时把本地新时间夹带进去,再次发送给服务器。服务器也可以进一步的了解响应时间。
C/S两端通过类似步骤进行计算彼此延时/时差,同时会对实时同步设置一个阀值,比如对延迟低于10ms(0.01秒)的交互认为是即时同步发生,不会认为是延迟。
每个移动包都含有一个序号, 当出现服务器强拉客户端位置时, 位置序号大幅度提高 。 以忽略在强拉信息未到时客户端的过程中, 客户端还在持续的向服务器发送移动信号, 避免位置逻辑混乱
UDP或TCP
不同类型的游戏会钟爱不同的协议呢,不一而足:
- 客户端间歇性的发起无状态的查询,并且偶尔发生延迟是可以容忍,那么使用HTTP/HTTPS吧
- 客户端和服务器都可以独立发包,偶尔发生延迟可以容忍(比如:在线的纸牌游戏,许多MMO类的游戏),那么使用TCP长连接吧
- 客户端和服务器都可以独立发包,而且无法忍受延迟(比如:大多数的多人FPS动作类游戏Quake、CS等,以及一些MMO类游戏),那么使用UDP吧
TCP会认定丢包是因为本地带宽不足导致(本地带宽不足是丢包的一部分原因),但国内ISP可能会在自身机房网络拥挤时丢弃数据包,这时候可能需要快速发包争抢通道,而非TCP窗口收缩,UDP没有TCP窗口收缩的负担,可以很容易做到这一点。
要求实时性放在第一位的FPS游戏(eg:Quake,CS),广域网一般采用UDP,因可容许有丢失数据包存在(另客户端若等待一段时间中间丢包,可以通过插值等手段忽略掉),一旦检测到可以快速发送,另不涉及到重发的时候UDP比TCP要快一点嘛。但会在UDP应用层面有所增加协议控制,比如ACK等。
很多时候协议混用,比如MMO客户端也许首先使用HTTP去获取上一次的更新内容, 重要信息如角色获得的物品和经验需要通过TCP传输,而周围人物的动向、NPC移动、技能动画指令等则可以使用UDP传输,虽然可能丢包,但影响不大。
现在出现了新的KCP, 即用UDP的来模拟TCP, 调整了重发策略, 从大大减少了包延迟。
总结
网游通过客户端预测、插值和服务器端延迟补贴等,化解/消除用户端网络延迟造成的停顿。