SuperSocket:GitHub,SuperSocket 2.0 中文文檔。
本文開發環境:Win10 + VS2019 + .NetCore 3.1 + SuperSocket 2.0.0-beta.8。
Gitee:SuperSocketV2FixedHeaderSample。
本文使用SuperSocket 2.0創建基於固定頭協議的Socket服務器,能夠滿足大部分自定義協議的服務器需求。本文使用協議如下所示,圍繞該協議說明PipelineFilter、PackageInfo、IAsyncCommand、AppSession、SuperSocketService等SuperSocket2.0元素是如何構建一個完整服務器的。
本文盡可能的將實現Socket服務器的類的作用說清楚,基本上就沒什么代碼了,具體可以參考Gitee相關項目。
0、准備工作
使用VS2019創建一個基於.NET Core的控制台程序,這里目標框架選擇了.NET Core 3.1。
使用NuGet工具搜索SuperSocket(需要勾選“包括預發行版”),選擇最新的版本(目前是2.0.0-beta.8)安裝。
在項目根目錄添加appsettings.json配置文件,並設置其文件屬性為“如果較新則復制”。(參考SuperSocket 2.0學習02:通過配置啟動 SuperSocket)。
1、PipelineFilter
SuperSocket 2.0使用PipelineFilter來處理應用層通信協議,其內置的FixedHeaderPipelineFilter實現了頭部格式固定並且包含內容長度的協議,從這個類繼承就能實現解析自己業務相關的固定頭協議處理類。
FixedHeaderPipelineFilter的構造函數需要傳入包頭大小,其余的包內容即為數據內容。根據我們的協議,包頭大小為4,因此將4傳入base類的構造函數即可。
其次是獲取數據長度,通過重載GetBodyLengthFromHeader實現。我們只需要在傳入的buffer中跳過2個字節,(以大端方式)讀取一個short類型數值即可,因為長度是2個字節。被我們跳過的字節很有用,會在解包時候保留該字節。
然后是通過重載DecodePackage解包,前面2個字節是類型,然后2個字節是數據長度,剩下的字節就是包體內容了。2個字節的類型,用於區分是什么命令,因此這里的類型和具體的命令就聯系起來了。
2、PackageInfo
前面解析了固定頭協議的數據包,就得有數據結構存放包數據,這就用到了PackageInfo。
PackageInfo需要作為PipelineFilter的泛型類型參數,以便在解包的時候能夠獲取對應包的對象。根據我們定義的協議,代表包類型的前2個字節是需要保存的,然后是包體字節。至於2個長度字節,則在進行包校驗的時候是必須保留的,否則就可以在PackageInfo類型中將其舍棄。
不得不說,僅僅如此是不能夠實現固定頭協議的命令映射的。SuperSocket2.0中的命令接口IAsyncCommand如果添加了Command標記,其泛型參數PackageInfo類型就必須實現IKeyedPackageInfo接口,以便將Command標記中的Key參數和IKeyedPackageInfo實例中的Key字段做映射。
我們的協議中Type是2個字節,因此將short類型作為IKeyedPackageInfo的泛型參數就再合適不過了,只是在解包的時候需要處理好大端小端的問題,以便獲取正確的short類型Key值。
3、IAsyncCommand
SuperSocket2.0中的命令類MyCommand需要實現IAsyncCommand接口(我們默認都是異步命令),在其ExecuteAsync方法中處理前面實現的PackageInfo對象。
要將MyCommand類和具體的Type進行綁定,需要在MyCommand類中添加Command屬性,標記其Key值為對應的協議即可。根據前面描述,其類型為short。如果Type為0xFF, 0xFE,那么MyCommand標記如下:
/// <summary> /// 0xFF 0xFE /// </summary> [Command(Key = unchecked((short)(0xFF * 256 + 0xFE)))] public class MyCommand : IAsyncCommand<MyPackageInfo>
這樣,MyCommand類就能將對應協議的Type類型對應起來,並在ExecuteAsync方法中對其進行業務處理。
4、AppSession
根據官方描述,AppSession代表一個和客戶端的邏輯連接,基於連接的操作應該定於在該類之中。你可以用該類的實例發送數據到客戶端,接收客戶端發送的數據或者關閉連接。
對於實現固定頭協議來說,AppSession不是必須的,但是站在應用服務器的角度來說,一個AppSession對象就是一個客戶端連接,該客戶端起碼會含有標識自己的信息,這是應用服務器所需要的。
AppSession是面向應用業務的類。
5、SuperSocketService
官方所述,SuperSocketService代表了監聽所有客戶端連接的服務器實例,宿主所有連接。應用程序級別的操作和業務邏輯可以定義在里面。
說白了,SuperSocketService就是實實在在的一個服務器對象,是應用級別的。在這個類中可以向用戶連接批量發送數據,比如進行一些事件監聽的客戶,在數據更新時候通過SuperSocketService可以跟注冊監聽的用戶同步。
但是SuperSocket2.0又支持多服務器實例,多服務器實例在.NET Core中是使用一個進程承載的,每個實例以HostedService的形式在進程(Host)中運行。如果要實現多進程或多服務器運行,需要使用Docker等容器技術。
6、Main函數
控制台程序的入口就是這里了,在這個函數中可以進行SuperSocket宿主的創建,命令、AppSession以及SuperSocketService的注入,配置日志等。總之,和.NET Core服務相關的配置都在這里進行。最后,宿主執行RunAsync方法就將Socket服務器啟動起來了。