帧同步的一个思路

    关于游戏网络同步这块之前有研究过很久,但是毕竟自己只是一个前端开发,对后端许多技术并不是很了解,之前自己写的基于supersocket+protobuf的框架也搁置了很长时间了,最近又突然想了一想之前的写法消息是服务器收到之后通过固定频率直接转发给其他客户端的,其他客户端收到后立刻执行。因为网络可能有延迟的缘故这样在处理一些消息是会有问题的,例如服务器广播一个关键消息客户端C1和C2是不可能同时执行的,中间存在的延迟就可能引发许多不同步的问题。当时还做了一个测试:VR下客户端C1主动投掷一个球但因为延迟等原因导致C2端显示最终球的落点和C1不同步(除了网络延迟还牵扯到了unity物理引擎随机数导致结果不同步)。后来尝试用帧同步的思路解决这个问题,但仍然只是一个思路。因为长时间没有写后端了,最近还要学习lua的相关知识所以没有时间实践,所以在此记录一下,有些地方也许考虑不严谨欢迎探讨。

先贴一张帧同步图解:

    

    如图,帧同步在解决延迟问题的解决方法是通过自定义一个逻辑帧来保证每个客户端在同一时刻执行对应的消息。刚才vr投球的测试中假设前方有一辆正在移动的汽车,C1没有延迟所以直接收到了服务器投球的消息,投出的球砸中了汽车,而C2因为延迟晚了1000ms才收到投球消息,此时汽车已经开走,所以C2最终执行结果就是球砸不到汽车,两个C端球的最终位置就无法同步。

    在状态同步下可能服务器需要进行一个验证,在收到C1投球消息后由服务器判断是否命中汽车并返回结果给客户端。球的最终位置也可以由服务器确定后广播,在此期间球的物理动画客户端可以预测表现,之后收到服务器最终位置后进行拉扯实现同步。在延迟过大的情况下可能拉扯会比较严重,但是好在可以进行一定的优化,并且关键事件(命中汽车,球最终落点)都完成了同步。

    如果用帧同步再来理一下这个过程的话,客户端和服务器就必须要加入逻辑帧了,客户端中逻辑帧处理速度要比渲染帧慢一些,例如可以规定1s执行30次逻辑帧,逻辑帧的开始由服务器广播,消息包加上时间戳,客户端在收到时间戳后可以计算出当前消息延迟(RTT),这样客户端与服务器就可以在同一时间开始执行逻辑帧。效果就类似上图。此时服务器会在每一帧时间戳广播上一帧收到的所有消息。消息包包含了当前逻辑帧序列号。这样的话如果C2出现1s延迟,在收到服务器消息包时可能已经往后执行了n个逻辑帧。而C2也可以根据消息包含的逻辑帧序列号判断出这条消息是属于n帧之前的,此时C2端就需要进行一个逻辑帧回滚,返回到n帧前并且以更快频率执行逻辑帧直至追赶到当前时间。在例子中的话帧同步服务器可能并不记录汽车的位置信息,所以此时渲染帧也需要进行一个回滚,渲染帧回滚可以参考这篇文章:

http://blog.csdn.net/su9257/article/details/54894228 。与文章不同的是回滚速度更加的快;

    这样子的话帧同步下服务器并不储存太多信息,仅仅是负责消息的转发。但目前来看很多游戏考虑到反外挂和稳定性在服务器上也增加了许多功能,例如守望先锋即使是帧同步服务器也会预测玩家的许多行为做校验,另外还会根据当前网络延迟动态改变客户端与服务器的RTT频率。

    另外所写的帧同步和状态同步并没有实践过,之前自己写的demo只是实现了最基本的消息转发,两种同步都是自己参考了一些文章琢磨出来的。以后如果有时间的话也许会实践一下,不过首先需要把原来的框架改成udp协议的,而且UDP下丢包和包序列问题还需要想办法解决,写的这段内容主要是身边没有可以探讨这类问题的人,许多问题只能自己琢磨,干脆就写个总结,以后遇到大牛多做请教再做修改吧。

参考:

《守望先锋》架构设计与网络同步

http://gad.qq.com/article/detail/28682    

 从王者荣耀聊聊游戏的帧同步

http://gad.qq.com/article/detail/32563   

子弹打没打中?这是个问题!

http://gad.qq.com/lundao/detail/10000117?sessionUserType=BFT.PARAMS.235548.TASKID&ADUIN=549297336&ADSESSION=1505200425&ADTAG=CLIENT.QQ.5533_.0&ADPUBNO=26719  

MOBA类游戏是如何解决网络延迟同步的?

https://www.zhihu.com/question/36258781

猜你喜欢

转载自blog.csdn.net/a549297336/article/details/79354022
今日推荐