需求介紹:由於網絡服務器是使用非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、二被我隱藏了