ET框架6.0分析三、網路通訊

寡人正在Coding發表於2023-05-15

概述

ET框架的訊息機制貫徹始終,包含Entity訊息(Awake,Update ...),自定義(Customer)訊息,網路訊息等。而ET系統的程式包含了客戶端、Gate等各種型別的伺服器,程式包含各種伺服器客戶端之間透過網路訊息進行通訊進行工作。

ET框架訊息結構

image

  • 結構圖為了更加明確整體關係,進行了一定程度的簡化,剔除掉了一些訊息解包等一些細節

  • NetCompontent網路元件有Client客戶端、Server伺服器(Gate)、Inner內網服務等多型,程式業務使用網路元件進行通訊,網路元件會對連線建立一個Secsiom會話物件,封裝連線資訊和相關操作

  • Service和Channel實現負責NetCompontent和Session的功能,有Tcp長連線、Web網頁、KCP無連線可靠協議的多型(若不熟悉KCP協議,可以參考之前寫的文章 跳轉連結: KCP協議淺析)。

    • Channel對應一個Session連線,封裝了對底層tcp等協議庫的操作。
    • Service對應一個NetCompent元件,對應NetCompent管理多個Session,Server管理和排程一堆Channel的工作。
  • NetServices負責排程多個Service物件的在網路執行緒和主執行緒工作任務,ET開了網路執行緒處理網路相關,某些程式需要多個網路元件(比如Gate伺服器同時需要Server、Inner網路元件,接收轉發客戶端訊息)。

  • NetComponentOnReadEvent是不同型別網路元件的訊息處理器。

    • NetClientComponentOnReadEvent對應客戶端Client,處理普通訊息和RPC呼叫。
    • NetInnerComponentOnReadEvent對應伺服器內網型別Inner,處理Actor訊息
    • NetServerComponentOnReadEvent對應服務外網,處理Actor訊息、RPC呼叫、普通訊息

訊息通訊

以典型的TCP協議型別為例,其他實現類似,看圖相信都能理解,不多贅述。有一些要注意的點:

  • 如上述,ET開了一個執行緒處理網路相關,一些工作使用了“生產-消費”Task任務這種方式。
  • 使用了非同步Socket

TCP發訊息

image

TCP收訊息

image

多程式呼叫

ET框架在基礎網路訊息通訊基礎使用了Actor模型、PRC等相關技術思想(某些思想和實現有調整)進行了擴充,提供多個程式的互相呼叫機制。
先對相關技術做一個簡介:

  • Actor模型

在電腦科學中,Actor模型(Actor model)是一種併發運算上的模型。“Actor”是一種程式上的抽象概念,被視為併發運算的基本單元:當一個Actor接收到一則訊息,它可以做出一些決策、建立更多的Actor、傳送更多的訊息、決定要如何回答接下來的訊息。Actor可以修改它們自己的私有狀態,但是隻能透過訊息間接的相互影響(避免了基於鎖的同步)

這是維基百科中對於Actor模型的描述,簡單理解它就是提供了一種訊息機制避免了基於鎖的同步。一些經典的應用場景是多執行緒,在ET框架中它的應用場景是多程式,類似的它提供了一種機制:直接透過ID發訊息,不用關心例項在哪個程式。

  • RPC

分散式計算中,遠端過程呼叫(英語:Remote Procedure Call,RPC)是一個計算機通訊協議。該協議允許執行於一臺計算機的程式呼叫另一個地址空間(通常為一個開放網路的一臺計算機)的子程式,而程式設計師就像呼叫本地程式一樣,無需額外地為這個互動作用程式設計(無需關注細節)。RPC是一種伺服器-客戶端(Client/Server)模式,經典實現是一個透過傳送請求-接受回應進行資訊互動的系統

RPC機制透過一些手段抹平了不同程式的差異,使得程式間的呼叫可以和本地非同步呼叫一樣處理。

瞭解了這兩種技術,下面來看ET框架對其的應用和如何實現多程式呼叫的。

訊息協議型別

image
如上圖所示訊息型別分為三種:

  • Message 訊息,無需應答
  • Request 請求,對應一個Response應答
  • Response 應答,對應一個請求

注意Request和Response一定成對定義,且其Message一定包含一個RpcId欄位

訊息型別可以被字首修飾,修飾有三種:

  • None 客戶端與伺服器(Gate)之間不需要轉發的訊息。(注意這裡不是修飾字元不是"None",而是""表示沒有)
  • Actor 伺服器內網之間的訊息
  • ActorLocation 客戶端與伺服器需要轉發的訊息。

修飾字元可以修飾任意訊息型別,組合起來一共有9種訊息。
如這個登入到Gate的協議:

//ResponseType G2C_LoginGate
message C2G_LoginGate // IRequest
{
	int32 RpcId = 1;
	int64 Key = 2;  // 帳號
	int64 GateId = 3;
}

message G2C_LoginGate // IResponse
{
	int32 RpcId = 1;
	int32 Error = 2;
	string Message = 3;
	int64 PlayerId = 4;
}
  • C2G_LoginGate 在訊息名後面註明了訊息型別,並在訊息名上面註明了應答包的訊息型別,並且包含一個RpcId的欄位,這些都必須的,表示這是個不需要轉發的、需要應答的請求訊息。而訊息名字首只是方便理解,起到註釋的作用:表示這是Client程式傳送給Gate伺服器程式的訊息。
  • G2C_LoginGate 同上,是上述C2G_LoginGate請求的應答訊息。

Rpc呼叫過程

image
如圖所示,進行Rpc呼叫時,生成一個新的RpcID並帶入請求包中,同時把呼叫資訊存起來。對方應答時,會把請求包的RpcID傳入到應答包中。在收到訊息時如果是Resp型別訊息會呼叫OnResp方法,透過應答包的RpcID取出RpcInfo,透過RpcInfo取消呼叫RpcCall函式的非同步阻塞。

public static void OnResponse(this Session self, IResponse response)
{
	if (!self.requestCallbacks.TryGetValue(response.RpcId, out var action))
	{
		return;
	}

	self.requestCallbacks.Remove(response.RpcId);
	if (ErrorCore.IsRpcNeedThrowException(response.Error))
	{
		action.Tcs.SetException(new Exception($"Rpc error, request: {action.Request} response: {response}"));
		return;
	}
	action.Tcs.SetResult(response);
}

action.Tcs.SetResult會取消非同步的阻塞,執行await後面的語句,詳情見之前寫的文章 跳轉連結: C#非同步程式設計

Actor模型實現

在ET框架的設計中,Actor其實是一個帶有MailboxComponent的元件。其具體的實現方式,ET有比較詳細的文件說明,有實現思路和使用方式的介紹,這裡貼出來,不做贅述。
跳轉連結: ET Actor模型 官方介紹

參考連結

相關文章