探究UE4網路系列(二)、UE4網路核心類分析
轉載請標明出處: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和值複製的邏輯原理兩個方面繼續深入分析網路連線。
&n