转载请标明出处:http://www.cnblogs.com/zblade/

一、概要

前面分析了网络核心的基础类Socket/BSDSocket/SocketSubsystem/SocketSubsysteModule,其主要是用于基础的模块加载和socket连接。在此基础上,进一步的层次是NetDriver和Connection, 这两者并不是完全上下层的关系,更像是互相依托的关系。在实际的应用中会在NetDriver的基础上进一步封装出子类IpNetDriver。

所以本文就主要分析三大类:NetDriver/IpNetDriver/Connection。NetDriver还有个子类DemoNetDriver,主要用于replay,这儿就不再详细分析,需要的可以去深入研究一下。

二、三大基础网络核心类

2.1 基础类 NetDriver   

在每个单独的UE进程中,只会有一个NetDriver的实例,虽然具体的是UIpNetDriver,但是本质是一样,都是网络驱动类。NetDriver和NetConnection是互相依托的,简单的来说,就是构建NetDriver,然后注册NetConnection,在NetConnection中注册ActorChannel, ControlChannel,VoiceChannel等。在更新的时候,从World触发相关Tick,然后触发到NetDriver,然后逐个触发其上面的Connection。在NetDriver和NetConnection中会有一些和RPC相关的操作接口,当然RPC的主要操作还是在UChannel上,这个在后续文章会具体分析其原理。

2.1.1 主要变量 

NetDriver的主要变量有:

  • class UNetConnection* ServerConnection: 连接到的服务器Connnection,只在客户端才赋值
  • TArray<class UNetConnection*> ClientConnections: 连接到host的所有client connection, 这在host上才维护,注意这是一个数组,也就是可以有多个客户端在host上注册
  • TUniquePtr<PacketHandler> ConnectionlessHandler: 在连接初始化的时候会应用到
  • TWeakPtr<StatelessConnectHandlerComponent> StatelessConnectComponent: 在连接初始化的时候会用到
  • class UWorld* World: 当前NetDriver注册所在的World
  • TMap< TWeakObjectPtr< UObject >, TSharedPtr< FRepChangedPropertyTracker > > RepChangedPropertyTrackerMap; RPC相关的历史存储数据变量
  • TMap< TWeakObjectPtr< UObject >, TSharedPtr< FRepLayout > >RepLayoutMap; RPC相关的数据变量
  • TMap< TWeakObjectPtr< UObject >, TSharedPtr< FReplicationChangelistMgr > >ReplicationChangeListMap; RPC相关的数据变量

2.1.2 初始化和构造函数

构造函数主要是对一系列的变量进行赋值操作,然后对Control/Actor/Voices三种Channel的类进行注册。 完成构造后会有几个相关的初始化接口:

ENGINE_API virtual void PostInitProperties() override;
主要是初始化simulation相关属性,然后确定是否有timeout,然后注册level的加载的两个事件委托

ENGINE_API virtual void FinishDestroy() override;
销毁操作,清理服务器和客户端connection, 然后移除上面注册的两个事件委托

ENGINE_API virtual void Serialize( FArchive& Ar ) override;
序列化相关

ENGINE_API static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector);
添加到gc对象列表中,然后从当前replication相关数据中移除

其他和构建销毁相关的接口有:

InitBase:
  Common initialization between server and client connection setup
InitClient:
  Initialize the net driver in client mode
InitListen:
  Initialize the network driver in server mode (listener)
InitConnectionlessHandler:
  Initialize a PacketHandler for serverside net drivers, for handling connectionless packets
FlushHandler:
  Flushes all packets queued by the connectionless PacketHandler
InitConnectionClass:
  Initializes the net connection class to use for new connections
ShutDown:
  Shutdown all connections managed by this net driver
LowLevelDestroy:
  Close socket and Free the memory the OS allocated for this socket

2.1.3 RPC相关的接口

RPC的三个触发相关的接口:

  • TickDispatch:   handle time update,tick更新前的time更新
  • TickFlush:   ReplicateActors and Flush, 值赋值和刷新
  • PostTickFlush: PostTick actions tick更新后的刷新和清除操作

具体的RPC相关的接口:

  • PreCheckReplicateActors: Replicate之前的操作
  • FlushActorDormancy: 刷新处于睡眠状态的Actor
  • ForceActorRelevantNextUpdate: 强制刷新actor的关联关系
  • PreReplicateActors: actor进行值复制之前的操作
  • ServerReplicateActorsXXX: 以ServerReplicateActors开头的函数接口,都是服务器执行值复制的相关接口
  • ProcessRemoteFunction: 处理RPC函数调用的接口

 2.1.4 网络相关的接口  

NetDriver本身还是又和数据发送相关的接口,主要是:

LowLevelSend: 数据发送接口
ProcessLocalServerPackets: Process any local talker packets that need to be sent to clients
ProcessLocalClientPackets: Process any local talker packets that need to be sent to the server

 总结: NetDriver其实主要是初始化,RPC和值复制相关接口,对于值复制相关的接口,在后续的值复制操作中会详细的分析,这儿就不展开详细分析。

2.2 基础类 IpNetDriver

相比于其父类NetDriver,IpNetDriver主要负责具体的Tick和Socket的创建,所以整体的网络最终网络连接实例实在这儿进行的,当然部分还是沿用其父类的实现。

2.2.1 主要变量 

  • FSocket* Socket: 当前IPNetDriver关联创建的Socket
  • uint32 ServerDesiredSocketReceiveBufferBytes :Number of bytes that will be passed to FSocket::SetReceiveBufferSize when initializing a server
  • uint32 ServerDesiredSocketSendBufferBytes: Number of bytes that will be passed to FSocket::SetSendBufferSize when initializing a server.
  • uint32 ClientDesiredSocketReceiveBufferBytes: Number of bytes that will be passed to FSocket::SetReceiveBufferSize when initializing a client
  • uint32 ClientDesiredSocketSendBufferBytes :Number of bytes that will be passed to FSocket::SetSendBufferSize when initializing a client.

2.2.2 主要接口

1. InitBase

在host端,将connectionlesshandler重置为null,为后续的登录连接做准备。

2. InitConnect

在调用InitBase后,会对应的创建一个ServerConnection,然后初始化,并在这个ServerConnection中创建一个Control Channel,其实现为:

这个Control Channel会在后面的连接过程中被使用。

3. InitListen

初始化话监听相关,同时处理ConnectionlessHandler相关:

4. LowlevelSend

数据发送,具体看实现的cpp代码即可。

5. TickDispatch

每帧的更新,看具体的实现即可。

6. ProcessRemoteFunction

对RPC函数的操作,后面会详细的分析。

总结:IpNetDriver虽然作为具体的网络驱动类,其部分逻辑沿用父类,部分自我实现,具体的分析,最好还是和后面的RPC和网络连接一起分析比较好,这儿就忽略不具体分析,后面来具体补充分析接口的实现逻辑和流程。

2.3 基础类 NetConnection

上面的两个类只是简单的阐述其接口和变量,由于其作为网络连接的核心驱动类,在后面的网络连接初始化,值复制和RPC中会反复的提及和分析,所以就简单的分析了。NetConnection作为连接类,在数据收发和网络状态中具有重要的作用,所以先详细的分析这个类。

2.3.1 基本变量分析

NetConnection中的变量,主体还是和网络连接相关,主要可以分为以下几类:

1. 连接相关外部类  

  • class UNetDriver* Driver: 该connection所关联的NetDriver
  • class AActor* ViewTarget: 当前connection关联的actor
  • class AActor* OwningActor: 主要指当前connection所关联的controller(controller本身也是actor)

2. 网络配置相关数据

  • int32 MaxPacket; 最大packet size
  • int NumPacketIdBits; 当前packet中PacketId所占bit数目
  • int NumBunchBits: 当前packet中的bunches所占bit数目
  • int NumAckBits: 当前packet中ack所占bit数目
  • int NumPaddingBits: 当前packet中Padding所占bit数目
  • int32 MaxPacketHandlerBits: the maximum number of bits all packet handlers will reserve
  • enum{ MAX_CHANNELS = 10240 }; 最大的channel数目,当然每个项目可以自己修改数目,现在10240对于有的有点过大

3. 网络连接相关

  • EConnectionState State       当前网络连接状态:Invalid/Closed/Pending/Open
  • uint32 bPendingDestroy:1;        true的时候,表明当前controller或则client正在被销毁,标志位
  • TUniquePtr<PacketHandler> Handler:     PacketHandler,主要用来管理packets的收发
  • TWeakPtr<StatelessConnectHandlerComponent> StatelessConnectComponent:          主要用来指向PacketHandler component, 用来管理无状态连接的握手处理,后面在网络初始化的时候会分析讲解
  • bool bNeedsByteSwapping:      当前数据是否需要交换byte
  • FUniqueNetIdRepl PlayerId:     这个id只在客户端有效,在server端保存这个id,用来表明remote连接的client

其余还有连接时的各种数据,主要分为连接时的数据,连接时的时间变量,以及网络stat相关数据,这儿就不再具体分析了。

4. Packet相关 

  • FBitWriter SendBuffer: 发送的buffer, queued up bits waiting to send
  • double OutLagTime[256]: for lag measuring
  • int32 OutLagPacketId[256]: for lag measuring 延迟优化相关
  • int32 OutBytesPerSecondHistory[256]: for saturation measuring
  • float RemoteSaturation:
  • int32 InPacketId: full incoming packet index
  • int32 OutPacketId: most recently sent packet
  • int32 OutAckPacketId: most recently acked outgoing packet

5. Channel Table相关

  • class UChannel* Channels[MAX_CHANNELS];
  • int32 OutReliable[MAX_CHANNELS];
  • int32 InReliable[MAX_CHANNELS];
  • int32 PendingOutRec[MAX_CHANNELS];
  • TArray<int32> QueuedAcks, ResendAcks;

6. RPC相关变量

  • TMap<TWeakObjectPtr<AActor>, UActorChannel*, FDefaultSetAllocator, TWeakObjectPtrMapKeyFuncs<TWeakObjectPtr<AActor>, UActorChannel*>> ActorChannels; 简单明了,每个actor一个channel
  • TMap<FNetworkGUID, TArray<class UActorChannel*>> KeepProcessingActorChannelBunchesMap: This holds a list of actor channels that want to fully shutdown, but need to continue processing bunches before doing so
  • TMap< TWeakObjectPtr< UObject >, TSharedRef< FObjectReplicator > > DormantReplicatorMap 睡眠actor列表
  • TSet<FNetworkGUID> DestroyedStartupOrDormantActors

2.3.1 基本接口分析

主要分为以下几种主要接口:

 1. 构造相关的接口

InitBase接口
初始化该Connection的实例基本设置,主要为设置stat相关的初始时间,设置handler,创建packagemap, 以及创建一个voice channel, 不过voice channel 基本现在不常用,相关接口可以暂时不关注

InitHandler
在上面接口中会执行InitHandler, 会执行MakeUnique来创建一个Handler,然后设置其mode为client还是server,初始化委托,并创建statelessconnectcomponent,为后面的握手操作设置。

InitConnection
这个相对于InitBase,主要没有Handler的设置相关,stat的设置相关,这个主要用于DemoNetDriver中的设置,DemoNetDriver主要用于回放系统

InitSequence
在握手完成后基于握手的数据重新设置InComingSequence/OutgoingSequence

EnableEncrytionWithKeyServer/EnableEncryptionWithKey
设置加密的key

Close
会将所有的Channel关闭,然后执行一次FlushNet

CleanUp
对所有子NetConnection执行CleanUp, 然后执行Close, 然后区分当前connection为server还是client,分别执行对应的connection的置空和remove操作,最后当前connection上的所有openchannel/actorchannel执行cleanup, 置空handler和Driver等一系列置空清除操作

FinishDestroy
调用CleanUp

AddReferencedObjects
将当前对象添加到可GC列表中

2. 数据接收相关接口 

ClientHasInitializedLevelFor
returns whether the client has initialized the level required for the given object

ValidateSendBuffer:项目改进的接口
当前sendbuffer是否有效

InitSendBuffer
初始SendBuffer

ReceivedRawPacket(void InData, int32 Count)*
接收到rawpacket,重点接口,如果handler不为空,则执行InComming的数据接收到的校验,然后刷新接收到的数据的统计,然后构建FBitReader,执行ReceivedPacket

ReceivedNak
获取到重新发送的packet的操作, 其来在receivedpack

ReceivedPacket
重点接口,获取到packet的相关操作,主要有

  * 更新时间戳
  * 检测packet的packetId的合法性,只能递增,不能比当前packet更小,否则就被标记为乱序不执行后续
  * 分类执行,基于当前packet是否为ack进行区分执行
  * Ack的packet的执行分类
    * 判断当前packet是否为重发的Ack, 是则调用上面的ReceivedNak
    * 更新controller的Ping
    * 更新当前OpenChannels中的每个channel的ack状态
  * 非Ack的packet的执行分类
    * 将当前packet解析为bunch
    * 对bunch进行排序
    * 基于bunch的ChIndex进行校验,对应不存在的情况进行校验,如果不存在当前对应的channel,同时Control对应的channel没有创建,则返回
    * 如果control对应的channel存在,并且bunch对应的ChIndex对应的channel不存在,则执行对应的channel的创建
    * 在创建完channel后进行是否接收该创建的channel的校验,如果不通过,则close和delete该channel
    * 如果通过校验,则设置执行ReceivedRawBunch
    * 刷新计数,校验Bunch
  * 发送回ack packet: SendAck

3. 数据发送相关

WriteBitsToSendBuffer
主要是创建SendBuffer对应的FBitWriterMark,然后序列化数据进去,具体发送的时机,要么是当前操作完成后,已经填满buffer,则触发flushnet,否则等待下一次flushnet的时候执行LowLevelSend才会执行send

SendAck
发送Ack包,只限制在非replay得情况下,对Ack对应得FBitWriter进行数据填充和序列化,然后调用WriteBitsToSendBuffer

SendRawBunch 对channel中发来的Bunch数据再进行包装一层后发送出去,调用WriteBitsToSendBuffer

4. Tick

Tick的基本操作可以分为几个部分:

  • 基本时间刷新:主要是各种stat的时间,更新的时间,以及超时的判断
  • 如果超时,则执行Close操作
  • 如果没有超时,则执行更新,主要更新:集中刷新发送Ack数据包
    • ChannelsToTick数组中元素的更新
    • OpenChannels的元素更新
    • KeepProcessingActorChannelBunchesMap字典中value的更新
  • 处理连接过程中的FlushNet
  • 集中处理刷新发送Handler中的rawpacket/packet数据包
  • 做一个数据统计

所以基本的还是数据统计,channel更新,handler中packet的相关刷新发送

5. FlushNet

FlushNet,相当于Flush操作,将当前缓存积累的数据都进行一次flush操作。函数操作比较长,但是主体的操作就是:将当前的sendbuffer中的数据执行 LowLevelSend操作来发送出去,然后刷新对应的相关计数和统计数据

6. RPC相关

NetConnection不是RPC的主要战场,会有部分与RPC相关的接口,主要是对Dormancy的actor进行刷新的操作:

FlushDormancy
对当前actor以及actor的cpnt进行FlushDormancyForObject的操作

FlushDormancyForObject
对当前DormantReplicatorMap字典中的对象进行dormancy state的判断,为后面的replication操作做准备

7. 登录相关

SetClientLoginState
设置客户端的loginstate

SetExpectedClientLoginMsgType
在服务器上设置期望下次客户端在登陆时候发送的msg type

IsClientMsgTypeValid
和上面对应的msg type进行比对

总结: 其实从接口分析来看,NetConnection主要的就是构造初始化,断开相关,对Packet数据进行收发相关,以及和登录RPC部分相关的接口,具体RPC的操作,还是需要在对应的Channel中进行仔细推敲分析,后面回进一步的分析到RPC相关。

在完成基本类的分析后,后面还会有对UChannel这个类的详细分析,但是其最好是和值复制以及RPC具体挂钩分析更佳。下面会分为网络连接的流程,RPC和值复制的逻辑原理两个方面继续深入分析网络连接。

探究UE4网络系列(二)、UE4网络核心类分析的更多相关文章

  1. Tomcat 学习进阶历程之Tomcat架构与核心类分析

    前面的http及socket两部分内容,主要是为了后面看Tomcat源代码而学习的一些网络基础.从这章開始.就開始实际深入到Tomcat的'内在'去看一看. 在分析Tomcat的源代码之前,准备先看一 ...

  2. Spring5源码解析系列一——IoC容器核心类图

    基本概念梳理 IoC(Inversion of Control,控制反转)就是把原来代码里需要实现的对象创建.依赖,反转给容器来帮忙实现.我们需要创建一个容器,同时需要一种描述来让容器知道要创建的对象 ...

  3. keystone系列二:keystone源码分析

    六 keystone架构 6.1 Keystone API Keystone API与Openstack其他服务的API类似,也是基于ReSTFul HTTP实现的. Keystone API划分为A ...

  4. disruptor笔记之二:Disruptor类分析

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. Android系列之网络(二)----HTTP请求头与响应头

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  6. openstack-- neutron 二/三层网络实现探究

    引出 Neutron 是openstack 中提供网络虚拟化的组件,根据二层网络的实现方式不同(即agent的不同),可以分为Linux bridge的方式,Openvswitch的方式.而且,lay ...

  7. Alamofire源码解读系列(七)之网络监控(NetworkReachabilityManager)

    Alamofire源码解读系列(七)之网络监控(NetworkReachabilityManager) 本篇主要讲解iOS开发中的网络监控 前言 在开发中,有时候我们需要获取这些信息: 手机是否联网 ...

  8. 百度APP移动端网络深度优化实践分享(二):网络连接优化篇

    本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<二>连接优化>,感谢原作者的无私分享. 一.前言 在<百度APP移动端网 ...

  9. Windows Server 2012 虚拟化实战:网络(二)

    关于Windows Server的虚拟化网络,前文描述了在操作系统层面上的出现的配置变化.其中的一些配置通过Windows Server提供的小工具即可实现,如网卡组的配置,而有些需要安装Window ...

随机推荐

  1. PHP是怎样重载的

    PHP 的重载跟 Java 的重载不同,不可混为一谈.Java 允许类中存在多个同名函数,每个函数的参数不相同,而 PHP 中只允许存在一个同名函数.例如,Java 的构造函数可以有多个,PHP 的构 ...

  2. pycharm设置python脚本模板

    PyCharm PyCharm是一个有名的Python IDE,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试.语法高亮.Project管理.代码跳转.智能提示.自动完成 ...

  3. vue 父子组件传值,兄弟组件传值

    父子组件中的传值 父向子    v-bind props <!-- 组件使用v-bind传值 --> <router :msg="msg"></rou ...

  4. Feature Fusion for Online Mutual Knowledge Distillation (CVPR 2019)

    一.解决问题 如何将特征融合与知识蒸馏结合起来,提高模型性能 二.创新点 支持多子网络分支的在线互学习 子网络可以是相同结构也可以是不同结构 应用特征拼接.depthwise+pointwise,将特 ...

  5. 新闻实时分析系统-Flume数据采集准备

    Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集.聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据:同时,Flume提供对数据进行简单处理,并 ...

  6. webuploader 快速应用(C#)

    百度的WebUploader前端插件作为目前比较好用且免费的附件上传工具,利用了断点续传特点实现了大文件上传功能,其更好的兼容性与界面效果完全可以替换掉IE的activex 上传控件.许多人或许还不知 ...

  7. 深度学习解决NLP问题:语义相似度计算

    在NLP领域,语义相似度的计算一直是个难题:搜索场景下query和Doc的语义相似度.feeds场景下Doc和Doc的语义相似度.机器翻译场景下A句子和B句子的语义相似度等等.本文通过介绍DSSM.C ...

  8. 【Android - 进阶】之Dialog分类及使用

    1.确定取消对话框 代码: // 使用AlertDialog.Builder初始化对话框 AlertDialog.Builder builder0 = new AlertDialog.Builder( ...

  9. Prometheus 安装

    目录 简介 安装部署 环境准备 安装 配置环境变量 配置 启动 简介 prometheus存储的是时序数据,即按相同时序(相同名称和标签),以时间维度存储连续的数据的集合. 时序(time serie ...

  10. [ch04-03] 用神经网络解决线性回归问题

    系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI, 点击star加星不要吝啬,星越多笔者越努力. 4.3 神经网络法 在梯度下降法中,我们简单讲述了一下神 ...