UE4网络同步思考(一)---经典同步方案

UE4网络同步思考(一)---经典同步方案

https://zhuanlan.zhihu.com/p/56548096

思来想去还是在开篇写一下自己相对比较熟悉的网络模块,因为它对于刚入门做网游的同学来说,是一个必须要攻克的知识点,可以作为联网Gameplay开发学习的入门着手点。

看了下知乎上已经有几位大神详细介绍了经典同步方案,从详细程度上还是要首先推荐

Jerish:《Exploring in UE4》网络同步原理深入[原理分析]​zhuanlan.zhihu.comUE4网络同步思考(一)---经典同步方案

内容非常详细,如能对比研读相关同步代码,一定会受益很多,我自己也很难在这个基础上再详实介绍了。另一篇

Jerish:《Exploring in UE4》关于网络同步的理解与思考[概念理解]​zhuanlan.zhihu.comUE4网络同步思考(一)---经典同步方案

以问答的方式介绍了实际使用过程中可能遇到的疑问,都是实实在在的一线干货,如有相关工程经验,读起来会颇有共鸣。

还有这篇

JettHuang:UE4网络模块浅析​zhuanlan.zhihu.comUE4网络同步思考(一)---经典同步方案

简洁干练地总结了收发端主要逻辑,也非常推荐阅读。

我这里想以比较容易理解的问答方式阐述下我对UE网络的理解:

1. 什么是网络同步?

多人游戏里面需要把某个玩家操作的结果通知给其玩家,这个通知的过程就是同步,再放到局域网或者广域网中进行,就是网络同步了。

2. 点对点还是中介转发?

点对点(P2P)就是N台机器相互直连,每台机器需与剩下N-1个机器建立连接,复杂度为O(N^2),而且增删机器也非常麻烦,对于大型网游来说这个方案基本不考虑。

中介转发就是我们常说的客户端/服务器模式(C/S),添加一个服务器作为中介节点,每台客户端只与服务器建立连接,客户端与客户端彼此独立,服务器负责转发消息。这种架构的复杂度仅为O(N),维护起来也方便,所以网游几乎清一色的采用这套架构。

3. 帧同步还是状态同步?

帧同步是服务器将某个玩家的输入直接转发给其他玩家,自己不做处理。理论上所有客户端都以相同的初始状态开始,只要收到的输入相同,那么每时每刻的状态都会是相同的。

状态同步是服务器只同步影响游戏功能的某些重要状态变量,并且这些重要变量是在服务器运算出来的或者至少校验过的,客户端拿到这些状态变量后自行做本地的表现。

一般来说帧同步在实时性、节省流量方面比较好,状态同步则在安全性角度来说更胜一筹。具体选用哪种方案由具体游戏类型来决定,UE是在射击游戏基础上发展而来的,它默认的网络同步方案是状态同步,把决策权放在服务器上做,可以有效减少外挂,对于中途加入/断线重连也能天然支持。

4. TCP还是UDP?

TCP连接的优点是可靠稳定,但速度慢这个缺点导致它并不适合网游。但UE也并未照搬UDP连接方案,而是在这个基础上融合了TCP的优点,例如加入了乱序处理,以及对reliable的包丢失重传。可谓是各取所优,既保证了连接速度,也保证了可靠性。

5. UE如何同步重要状态变量?

保守的方法是把这些重要状态变量每时每刻都对所有客户端进行广播,但这样会造成流量的问题,也会带来客户端本地的计算复杂性。对于UE来说,需要同步的重要状态变量都存在于Actor这个容器里。UE网络同步的设计方案有以下两个特点:

(1)尽可能节省带宽:

相关性计算:对于像吃鸡这种大世界玩法,不需要每帧都同步一百个玩家的状态,对于A玩家而言,只需要同步他可以看到的或者会受到影响的那部分玩家就可以了,这就是相关性的计算。

优先级计算:判断相关后还会进行优先级计算,优先同步高优先级的状态变量,如带宽饱合则当帧不会同步低优先级的状态变量。

成员变量计算:需要同步的Actor里面会包含很多成员变量,但不是每个成员变量都需要同步,只有开发者打上网络同步标记的变量才会被同步,而且这个变量只有在服务器端发生变化了才会同步给相关的客户端,甚至还有额外标记控制同步,比如bNetInit只在刚建立同步通道时同步。

合包:每个包里都会有额外的包头信息,如果包拆得越细那么占用带宽就会越多,UE里面将多个Bunch(最小的同步单位)合入到一个Packet里面进行发送,再在收端分拆回Bunch进行逐个处理。

(2)尽可能可靠:

丢失重传:reliable的包在发端会保存一个备份,只有收到收端返回的Ack包确认后才会清掉,若收到的Ack包跳序则会触发重传。

Packet乱序整理:因网络链路复杂性,到达包顺序可能与发端不一致,这时会进行整理,对于分包导致的不完整的部分(Partial)包也会等待重组。

包头校验:包头存有内容块的大小,如果不符合,则会丢弃这个包,防止坏包带来的后续数据处理异常。

6. 成员变量同步还是远程函数(RPC)?

成员变量同步的持久性较好,RPC则是瞬发的,玩家断线重连后采用变量同步的方式仍是正确的,但RPC同步的东西却不会再重放。

成员变量同步仅发生在服务器到客户端,RPC则是双向的,如果想客户端同步给服务器什么东西,那没得选只能RPC。

RPC的实时性比成员变量好,因为RPC调用是瞬时发到远端执行的,而成员变量同步还要等packet满了之后才发车,不过这个因素其实不那么重要,两者相差很小。

7. 如何正确又优雅地使用UE网络同步功能?

提三点建议:

其一:一开始做功能先别管网络,优先单机,单机表现不正常剩下的都是白谈。

其二:大概看下UE官网对于网络同步的使用,知道有哪些关键字(不多很简单),再结合自身项目代码或者ue4的sample工程(如shooter game),看下别人如何使用的,理解后学以致用,写好后在编辑器里面选2人勾DedicatedServer跑下是否正常。值得一说的是,UE4新加了component的同步,要善用这个模块化的利器,不必像UE3一样把同步变量都堆在Actor上。

其三:知其然更要知其所以然,使用起来方便但背后设计却非常复杂,要静下心下跟跟代码,看看前面几位大神的文章,对网络实现细节深入理解。

 

UE4.20版本针对大世界推出了一套新的网络同步方案RepicationGraph,解决50000+对象同步问题,这块知乎上提的人比较少,我打算下一篇中介绍,详见:

Jerry:UE4网络同步思考(二)---大世界同步方案​zhuanlan.zhihu.com

 

 

 

 

 

 

 

 

 

 

 

 

 

 

上一篇:ue4的GamePlay框架


下一篇:UE4场景流程规范-纹理压缩设置(美术版/程序版)