外链论坛

 找回密码
 立即注册
搜索
查看: 39|回复: 1

对抗网络延迟 手游服务器实时同步办法分享

[复制链接]

2525

主题

4642

回帖

9998万

积分

论坛元老

Rank: 8Rank: 8

积分
99981029
发表于 2024-8-31 04:38:37 | 显示全部楼层 |阅读模式

网络延迟是所有实时同步的游戏都会遇到的问题,下面是关于实时同步问题的有些思考和处理办法详细处理办法可能比较特殊,首要这儿的服务器并不跑按时器(除了一个游戏结束倒计时的按时器),由前端驱动,延迟的状况重点是由于前端来预测或纠正,服务器辅助,处理和转发,据我的认识好似没什么人这般子搞吧。因此看完倘若觉得我这边有思虑不周的,有更好的思路,欢迎拍砖 / 交流。首要这是一个两边出兵对攻的游戏,仅有2个玩家,而战场上士兵/英雄的数量不会太多,最多不会超过50个吧,士兵都是有AI的,不被玩家掌控。玩家能做的操作特别有限,这儿只以出兵这个操做为例。在游戏起始的时候,会有一次校时操作,这个后面会说到。玩家A在Tick1点出兵,播放各样出兵特效之后,Tick1 + Delay = Tick2,在Tick2这个时间才会真正出兵,Delay等于抬手时间,便是一个准许的延迟时间,并不等于网络延迟,应该理解为一个前摇动画的播放时间,这个时间越长越好,在不影响玩家体验的前提下(例如弄一个士兵生产队列,从出兵指令发出到士兵生产完毕,这可需要不少时间)。此时候玩家请求服务器,请求的内容包括Tick1 + 出兵指令,服务器收到指令,对服务器而言,此时可能有两种状况第1种是在Tick2之前收到,第二种是在Tick2之后收到在Tick2之前收到,服务器能够转发操作,告诉所有的客户端,咱们在Tick2出兵(包的内容包括Tick2和出兵指令),此时候对另一一个玩家,他可能看不到出兵的特效,而是直接看到出兵,这问题,他看到的特效在时间上晚了有些,这都是能够接受的,不影响游戏规律的。这是前后端网络正常时的状况

在Tick2之后收到,服务器能够丢弃这个操作,立刻执行这个操作,此时已然是Tick3了,广播给所有玩家,在Tick3出一个兵,由于此时服务器已然是Tick3,那样客户端收到出兵指令的时间是已然过了的,此时候会引起客户端必定会进行一次纠正,那样咱们能够再延一延,让这个指令在Tick4再执行,Tick3 + Delay2 = Tick4。丢弃,Tick3,Tick4执行的结果分别是,玩家的操作无效,战斗需要经过一次纠正(纠正会引起玩家看到奇怪的东西),以及玩家的操作延迟了,然则看到的东西是正常的,只是我的操作晚了一段时间罢了服务器延迟执行这个指令,客户端在生效时间之前收到,大概是这般子的:

所有的指令从触发到生效都不是立即的,都是经过延迟的,哪怕我的网络延迟在1ms之内,我这个指令都要在delay时间之后才执行,而前后端都会有一个指令Queue,来记录在哪一帧应该执行哪一个指令。所有的指令,只要做到在第几帧执行的统一,就能够保准结果的统一。客户端接收到指令的时候,此时候又有2种可能,分别是在Tick2之前,以及Tick2之后。在Tick2之前收到,那样皆大高兴。在Tick2之后收到,那样咱们这个操作就延迟了,可能要进行纠正,这儿说可能,由于还有一线生机。便是玩家点出兵之后,并不等服务器返回,而是在Tick2时自动出兵,这般子的一个好处是,客户端在网络比较差的状况下,所有的东西都能够得到反馈。虽然这些反馈可能是错误的,然则不碍事,关键是玩家体验的流畅,错了最后肯定会被纠正,只要处理好纠正时候的表现就能够了。倘若自动客户端自动预测:

况且这般子做不必定是错的,倘若服务器在Tick2之前收到我的请求,那样服务器会在Tick2执行出兵的规律,而我在Tick2之后收到服务器的响应,但我在Tick2执行了出兵的规律,这是同一帧,这种状况下是不需要纠正的,由于虽然延迟了,然则咱们正确预测到了结果。需要纠正的有两种状况第1种是B玩家在Tick2之后收到,由于B玩家是没法预测到A玩家在Tick1点击了出兵,在Tick2出了一个兵。第二种是服务器在Tick2之后才收到,那样两个端可能都需要纠正,这儿说可能,由于还有另一的一线生机。倘若咱们不做预测,而是等服务器的结果,按照服务器的结果来执行,这种状况下,客户端的表现是流畅的,战斗是流畅的,只是我的点击立即反应罢了。服务器在Tick3下发(内容包括Tick4 + 出兵指令),在Tick4执行,客户端只要在Tick4之前能收到,就能够在Tick4执行出兵,那样结果是正确的。这种乃至咱们能够以服务器收到的时间为准,服务器每次收到都在当前时间的基本上延迟一段时间来执行,完全无视玩家点击的时间,只要客户端在这段延迟时间内收到结果,是不需要纠正的。这两种一线生机的区别在于,一个是忽略了包从服务器回来的延迟,一个是忽略了包到服务器的延迟,一个是保准客户端流畅,一个是尽可能避免纠正。详细要在实质环境中测试才可晓得,哪种更适合我们游戏。因为所有指令的执行会放在一个队列中,因此这几种方式的切换只需要改动少量的代码。当咱们拿捏不准的时候,尽可能让这部分能够被灵活地调节全部服务器这边的Tick机制便是能够被灵活调节的(由于我不跑按时器)。

最后便是纠正了,首要纠正是由于前端发起的,当而后晓得前端延了,后端的处理其实比较随意,无关紧要,前面说的,丢弃,立即执行,延迟执行,都是能够的,但看上去延迟执行是个更好的主意,这个详细游戏吧。前端怎样晓得自己延了,这个问题其实很简单,在战斗起始的时候进行一次校时,而后双方都以一致的频率,例如每秒10帧,从第0帧起始前进(实质上服务器只是记录一个时间,并不跑按时器)。其实前后端只要记录了第0帧的这个起始时间,是很容易算出当前是在第几帧的,前后端的这个起始时间并不相等,只是规律上相对罢了。当然,这个时间会存在误差,误差的结果便是,一边快一点慢一点。然则不碍事咱们不是根据时间来算,咱们根据帧来算,咱不需求同一个时间两个端的内容是完完全全的同样,咱只需求结果同样。例如一台设备性能很差,每秒5帧,然则他的结果不会错误,游戏10秒后结束,他这边就20秒后结束,但结束时的结果是同样的就行,至于操作,倘若存在这般的可能性,那服务器就把操作延迟执行,对前端罢了可能按下去要等好几秒才可响应,但此时候都已然不是网络延迟的问题,是设备卡顿的问题。前端始终在跑,然则不外来,要处理这个问题,只能是换手机,当然咱们自己要保准在性能很差的手机上能跑起来才行,例如两三年前的设备,但实质上咱不需要花太多心思在这上面,这个玩家这么烂的手机都不舍得换,怎么舍得往游戏里面充钱呢?直接放弃他了。服务器并不跑计时器,这是什么原由呢?有一部分是性能的原由每一个子弹,怪物,BUFF这些可能都需要挂计时器,我不期盼服务器挂太多的计时器。比很强的一部分是让拿捏不准的这部分更加的可控。例如这个游戏不做实时同步了,让事情变得不是那样糟糕。只需要少许的改动,就能够实现服务器的校验。不跑计时器怎么做呢?很简单,首要你还是需要有一个计时管理的,类似Schedule,游戏规律中添加的计时器全放到这儿面,当客户端请求的时候,咱们先从上一次计算的时间模拟到当前时间,将当前时间减去上次的时间,算出有N帧,而后直接 loop N次计时器,这个loop和客户端的loop相比,便是少了有些判断逝去时间是不是少于最小间隔时间,倘若是则sleep一下这般的代码,而改成为了一个for循环,循环N次。当然,loop的不必定只是计时器,然则必定包括计时器,况且重点便是计时器。loop完之后,将上次的时间记录为当前时间,而后进行校验,转发指令。此时并不执行指令,而是把经过校验的指令放入指令队列中,等待下次执行。指令执行的结果是什么,服务器此刻是不晓得的。能够看到是客户端的请求来驱动服务器,而不是计时器来驱动服务器运行规律。这就有点类似回合制了。那样还有一个问题,假设客户端都不发请求,那服务器不就动不了了?服务器会跑一个计时器,这个计时器只做一件事,便是游戏结束,模拟玩家发一个空的指令到服务器这边,服务器loop到游戏结束,而后下发战斗结果。不跑计时器,怎样让当这个游戏从实时同步变成非实时同步变得简单呢?能够这般子,客户端所有发送的指令,所有都在客户端直接运行,然则记录下来,而后在游戏结束时,请求一次服务器,将指令队列发给服务器,服务器只需要设置指令队列,而后执行一次loop到游戏结束的调用,自然能够校验到战斗结果。这个非实时同步的需要,本身便是存在的,例如单刷副本,这个咱们是需要校验的。因此只需要在外面进行一层包装,就能够替换她们况且改动的代码量并不多。

接下来还是说纠正的问题,当客户端发掘服务器下来的包延迟了,超过可接收的时间了,客户端需要向服务器请求最新的数据来刷新,这个过程中,客户端是正常运行的,而后当数据下来之后,大概花0.5-1秒的时候来刷新数据。将本地有服务器的对象干掉,本地服务器有的对象创建,两边都有的数据进行一个平滑的插值计算,让他在这段时间过渡到最新的数据。这儿必定会产生有些玩家看起来很奇怪的画面,在上面加一个正在重新连接...,玩家应该会比较能接受这小段看上去奇怪的画面。过渡的时间内,本地的实时规律帧是始终在正常运行的,它记录服务器当前运行到第几帧了,本地还有另一一个帧变量,这个变量暗示当前规律帧,这两个帧都是规律帧,正常而言,这两个帧是相等的,但当纠正出现时,当前帧会少于实时帧,例如第200帧发掘我本地需要纠正,而后请求服务器,服务器下发了最新,便是201帧的结果下来,到客户端这边,已然是207帧了,但重置到最新的数据,便是201帧,而后起始加速执行。执行到两个规律帧相等,即恢复正常速度执行。首要加速是可行的,由于服务器能够瞬间执行完,那样客户端为何不可加速执行完呢?最关键的是,每一帧的结果都是同样的,前面从200帧之前,客户端有一部分的结果就已然错误了,纠正的本质是把错误的结果丢弃,而后重新设置正确的结果。再继续运行。另一假设是客户端跑得太慢,跟不上服务器的话,那实质上服务器运用延迟执行的方式,基本上是不会有纠正的需要的,由于所有指令针对这台设备而言,都是未出现的,客户端只能慢慢跑,慢慢演示战斗结果。这般的设备上,动画都是一卡一卡的,问题已然从网络延迟的问题转变为设备的性能问题了,这是另一一个优化的专题了。规律帧和表示帧的分离,有这么几个目的,规律帧用来保准规律的准确性,便是这场游戏一共跑2000帧,执行2000次规律处理。这部分是前后端共用的。至于前端的表示刷新了8000帧,还是6000帧,影响的只是动画的平滑度罢了,不影响结果,前端花100秒还是200秒来跑完游戏,是不影响结果的。第二是方便纠错和加速,规律帧和表示帧的交互流程是这般的,每次规律帧执行的时候,会修改类似位置这般的属性,改变有些状态。表示帧负责平滑地从当前位置,状态改变到规律帧修改的位置和状态,并播放相应的动画。规律帧并不直接改变这些属性,而是将这些修改放到一个每一个对象特有的数据组件中,规律判断时,是取这些里面的数据来判断,而不是表示层的数据。每次更新,表示帧都会做一个从当前过渡到该数据的规律规律帧的频率加快了,对表示罢了影响的,两者互相独立,规律帧只管规律处理还有写数据,表示帧只管取出数据来进行表示客户端这边,规律帧和表示帧都是由于同一个Schedule来驱动运行的,但频率区别她们很强的一点区别是,规律帧每一帧的dt是一个固定的值,例如每秒10次规律帧,那样这个dt就固定是0.1,而表示帧是按照实质的逝去时间来做为dt的。这儿的dt指的是每次update传入的逝去时间。每次规律帧写入的数据除了位置状态等数据,还会包括一个需要表示帧在多长期内模拟完成的数据,这个是一个定值0.1。表示帧拿到位置数据,我要移动去哪,再拿到时间数据,多长期内移动到,那样能够执行平滑表示规律了。至于2G 3G的网络延迟,这个和PC的延迟有什么区别呢?一个是延迟会更大,另一一个便是不稳定。延迟的数据是多少,这个数据道理不是太大,由于这个数据仅有有些参考道理实质的延迟并不是根据这个数据来,而是很不稳定的。可能你蹲个厕所,把厕所门一关,信号一下子就差了非常多,这是很平常的。由于移动设备是可移动的,移动到区别地区都可能有区别的延迟,此时候可能有两个数据会比较有用,一个是2G 3G比较快的速度是怎么样,另一个是2G 3G比较慢的速度是怎么样。在这般差的网络下,必定会显现非常多次的延迟纠正,但只要咱们能收到信息,游戏就能够运行。客户端模拟是可以得到高延迟下好非常多的体验,由于每次点击都有反应,虽然真正生效的时间延迟了,但你的操作还是生效了。2G 3G的另一一个问题便是断线,断线重连其实又是另一一个略有蛋疼的专题了。在2G 3G下,在高延迟下给用户带来不差的体验,这个是实时同步比较难做到的,关键看游戏指令的可延迟性,实时需求的高低,玩家操作的频繁度,以及错误纠正时的体验,能否让玩家接受。倘若不行,那样就需要弱化它,例如在进入游戏之前,检测一下ping值,倘若太高,则提醒玩家,你当前的网络延迟较高,让玩家自己决定在不在高延迟的环境下游戏。实质针对网络延迟,绝大都数的玩家都不陌生,打了一剂预防针之后,对后面的反应不即时的体验包涵性会高一点。在延迟高的状况下,意见玩家去刷单机副本,是一个可行的方法另一,还有一个方法,虽然有点诈骗玩家,但只要玩家觉得游戏流畅就能够了,便是派AI的设备人跟高延迟的玩家打。全部同步的想法日前正在实验中,但理论上是可行的,看上去可能有些繁杂,但实质的代码框架搭建起来之后,代码写其实是很简洁的,由于所有的规律都不需要关注延迟。并且可能会变化的部分被隔离开了,每一个东西尽可能地独立。当然,在实现的过程中肯定是会碰到更加多的问题,有问题处理便是了,关键是要有思路,有处理问题的方向。全部想法的落地大概是这般的,前后端都是用的C++,前端是2dx,后端是kxserver,后端搭建一套模拟2dx的框架,实现一份简化版的Director,Schedule,Node,Component,而后制定编写规律关联组件的规则,用自己写的信息机制来传递信息,当有一部分规律需要执行到表示关联的内容时,能够用事件来处理,客户端存在这个监听者,而服务端不存在。另一能够运用预处理,按照是不是定义了Running In Server这般一个宏来预处理有些代码。设计中是分了比较多的层和模块,来保证万一哪个不行了,不影响到其他的代码。在落地的过程中会连续地完善代码,打磨,验证想法。期盼这个项目结束后,能沉淀下一套Cocos2d-x网络实时同步的规范和前后端简易框架,来复用到其他有类似需要的项目中。

回复

使用道具 举报

2615

主题

4828

回帖

9916万

积分

论坛元老

Rank: 8Rank: 8

积分
99160667
发表于 前天 21:26 | 显示全部楼层
祝福你、祝你幸福、早日实现等。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站点统计|Archiver|手机版|小黑屋|外链论坛 ( 非经营性网站 )|网站地图

GMT+8, 2024-10-3 18:29 , Processed in 0.065987 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.