需求介绍:由于网络服务器是使用非UE4的网络,须要在中间抽象出网络层和接口层,保证在平常开发和后期维护都很方便的前提下,与逻辑的耦合度不高。而且支持在无网络后台模块的状况下,单机运行也能有正常的效果,相似UE4 网络中 的server和standalone关系。html
UE4网络有一些很重要的概念,最重要的莫过于“同步”即“Replicate”面试
不只分普通Rep/RepNotify,还有Replicate和ReplicateMovement等细节的差异后面会提到,曾经有人面试回答问题UE4网络问题说,UE4网络就是同步么,虽然不完整但讲出了核心部分。api
第二个重要概念就是"代理"或是“模拟”即“simulating” ,它与Actor的Role相关,服务器
ROLE_None, /** Locally simulated proxy of this actor. */ ROLE_SimulatedProxy, /** Locally autonomous proxy of this actor. */ ROLE_AutonomousProxy, /** Authoritative control over the actor. */ ROLE_Authority,
能够简单近似的理解成是权限的意思,由于它与RPC调用紧密相关。网络
第三个就是RPCs的调用,主要是Server/Client函数,以及对应的标识(Muticast/RunOnServer/RunOnClient),RPC中的Reliable和Replicate单词看上去很接近,但很容易混淆,是两个概念意思。socket
因此在官方文档中,一个Actor的网络更新主要有“变量更新”和“RPC调用”两个方法来实现全部的网络过程。编辑器
UE4是C/S结构的网络,比较特殊的地方是,UE4的Server有两种(由于历史缘由,UE4是从FPS的结构中出来的)ide
Listen Server和Dedicated Server主要区别在Dedicated Server渲染上减小,额外的还有声音也不加载等等。函数
比较表层的应用和要注意到的问题能够参考 UE4网络同步详解(一)——理解同步规则 讲的仍是比较细致的性能
这里提炼一些比较有用的TIPS:
一、当有多个实例被建立时,GetLifetimeReplicatedProps函数并不会屡次执行。这也就是说,Lifetime的设置是基于类自己还不是基于类实例的,若是属性的同步由某一个状态值来定的话,那么全部的实例都会用第一个实例的状态来定,而不是根据本身实例的状态来定。
二、静态组件(C++构造函数里建立和蓝图内默认挂载的)的同步与该组件是否标记为Replicate是没有关系的。一旦一个Actor被标记为同步,那么这个Actor身上的静态组件也会随Actor一块儿同步到客户端
Bunch是”束“的意思,UE给的概念就是打包在一块儿的一些东西,一些包括:
FOutBunch/FInBunch 分别是Channel产生/接受的数据束(数据流)
在 Runtime/Engine/Public/Net/DataBunch.h中定义,继承关系为
Out下有一个特殊的:FControlChannelOutBunch
对控制写入有两个特殊限制,分别是不能发送FName和UObjects* 在ControlChannel中 由于它的设计是为了,创建和断开连接,不用它发送数据。
咱们能够看到父类的NetBitReader/Writer中
virtual FArchive& operator<<(FName& Name) override; virtual FArchive& operator<<(UObject*& Object) override; virtual FArchive& operator<<(FSoftObjectPath& Value) override; virtual FArchive& operator<<(struct FWeakObjectPtr& Value) override;
应该是特殊限制了前两个FName和UObject的操做,只能使用Soft/WeakObject的操做
为何ControlChannel不能有FName和UObject*的操做呢?猜想与这个通道的定位有关
通道主要用来区分了不一样数据类型的发送和接收。
从继承上看包括了(测试用UUnitTestChannel、Actor UActorChannel、连接控制用UControlChannel、声音UVoiceChannel)
Channel里处理了rawbunch和bunch作拆包、分包的问题。
UE4的网络驱动核心,控制管理Connection,channel等,以及socket链接,FSocket 不一样平台的Socket封装 ,FSocketBSD:使用winSocket的Socket封装。
ND还对网络数据的输入输出作总体的流量控制管理,debug统计
一个world控制着一个networkdirver,具体实现是 UIpNetWorkDriver,再下一级是Steam的Driver.
ClientConnection 是在服务器上,存储着和客户端链接的对象;
ServerConnection是在客户端上,存储着和服务器链接的对象;
UPackageMap:生成、管理Object与NetworkGUID的映射,负责Object的名字与自身序列化,通知Bunch提交,序列化新的actor,卸载streamlevel的通知。
每个Connection对应一个UPackageMap
(Packet与Bunch的区别:Packet里面可能不包含Bunch信息)Packets是一个概念,UPacket和其不是一个意思。
这里顺便提一句,UE4是服务器和客户端同一套代码,因此重写本身的游戏使用的网络时,有时候的需求只须要客户端的网络通讯部分,减小了大量服务器逻辑,而且UE4还要考虑多平台的逻辑,甚至还要有编辑器部分,网络部分就更加复杂不单纯了。
思考:错误的同步发送是在哪一层被UE4丢掉的呢?
ControlChannel的消息类型22条,其中几个比较常见的消息有
ControlChannel常见消息
消息 | 消息说明 |
---|---|
(Hello, 0, uint8, uint32, FString) | 首次握手消息 |
(Welcome, 1, FString, FString, FString) | 服务器返回握手,告诉客户端能够加载服务器关卡了 |
(Login, 5, FString, FString, FUniqueNetIdRepl, FString) | 客户端加入游戏消息 |
(Join, 9) | 最终加入请求(在释放PlayerController的时候) |
(JoinSplit, 10, FString, FUniqueNetIdRepl) | 分屏子玩家的加入请求(客户端有1P/2P分屏的时候) |
(DebugText, 17, FString) | 客户端服务器调试信息的消息 |
(NetGUIDAssign, 18, FNetworkGUID, FString) | 很特殊的状况才会发生,NGUID的一种操做,若是只序列化客户端到服务器的消息。若是是服务器发给客户端,就至少表面使用的ID。 |
UE4网络的内容还有不少细节的东西,包括同步的具体细节、网络性能均衡、网络资源管理统计等,但考虑只剖析到通讯基础流程上,不考虑上层实现应用的话,了解这些就清晰了,对自定义网络部分有很大的帮助。同时感谢参考中文章的做者们,帮后人铺好了路。
若是文中有任何错误的地方,欢迎纠正。
——————————————————————————————————————————————
几篇不错的网络分析博文,由浅入深的按照顺序去看
除此以外,了解到这部分的时候,顺便也要知道UE4的反射机制
———————————————————————————————————————————————
为何是笔记·三? 由于1、二被我隐藏了