近幾日想在一個項目中引進一個Socket Server,用來接收客戶端發送的命令消息並根據具體的業務邏輯對消息進行處理,然后轉發給其它在線的客戶端。因為以前在博客園關注過江大漁開源的SuperSocket,后來便在Github和Codeplex上一直關注該項目,但僅僅限於關注和了解。這次想通過具體的實踐進一步學習該框架。我覺得一個優秀的開源項目離不開漂亮的代碼、清晰的文檔、完善的測試、持續的更新,當然從普通走向卓越更離不開社區的支持(源碼、宣傳、案例及文檔等)。而SuperSocket對我個人而言是一個很優秀的開源項目,很值得去學習和應用。
在官方介紹里,SuperSocket是一個輕量級、跨平台、可擴展的Socket應用框架。用戶使用它可以很容易就構建出服務端Socket應用程序(如GPS Server、GIS Server、Game Server、FTP Server等),而不用去考慮關於Socket開發的具體細節(如socket如何使用,socket連接如何維護機器socket如何工作等)。常言“是騾子是馬,拉出來溜溜”,看看官方實現提供的文檔實例以及源碼中的QuickStart系列,就可以發現使用SuperSocket開發一個socket server,真是很方便。鑒於個人能力的問題,關於SuperSocket的使用和理解可能有所偏差,本文所述均為個人理解筆記。
SuperSocket的基本認識
關於Server的一點想法
Server是用來響應請求的,Ngnix、Apache、IIS作為Web Server,Oracle、MySQL、MongoDB、SQLServer作為數據庫Server,不同的角色決定了其擁有的功能和關注的痛點。比如Web Server主要是用來響應Http或Https協議的請求,其職責是盡可能快響應瀏覽器發出的請求(如圖片、CSS、JS等靜態文件的下載,表單數據的提交處理等),所以Server首先要專注的自己的核心任務所在,提供高性能、高質量服務。關於我自己項目中的Server需求很簡單,僅僅是個消息的轉發中心而已。
關於SuperSocket的數據處理流程的認識
編寫Web應用程序的時候,對從瀏覽器到Server中間發生的故事的了解程度反應了一個人對整個Web開發的大局觀,進而決定了所開發的程序的性能和質量。比如明白了請求從瀏覽器發出經由網卡進入互聯網,經過多個路由轉發跳轉最后進入服務器端的Server,到了Server端又會進入各種處理管道,后面涉及到如數據庫的訪問、日志的記錄查詢等處理,再原路返回給客戶端瀏覽器的過程,就理解了一個請求所耗費的各種時間,如路由器排隊時間、網絡傳輸時間、數據庫訪問時間、磁盤IO讀寫時間等等,也就能明白為什么各種各樣的緩存是優化性能的最好幫手。君不見無論是應用程序中一個全局配置的單例緩存還是構建在Web Server與數據庫之間的緩存服務器(Redis\Memcache),亦或是分布在祖國各地的CDN節點緩存,所有的緩存支持都是為了我們的Server提供更好的響應。
同樣,使用Supersocket進行程序設計的時候,也得明白其數據流程是如何處理的。在官方的文檔里面有一張圖很好的說明了SuperSocket的請求處理流程:
在上圖中很清晰的定位了SuperSocket Server所管轄的邊界,由於網絡中傳輸的數據包都是二進制流,如果是TCP還會有很多諸如粘包、拆包、組裝等各種問題,但是使用SuperSocket可以完全忽略這些問題,因為SuperSocket幫我們很好的處理了這些問題。
- 從連接請求到Session的創建: 當客戶端與Server端的Socket監聽端口成功建立連接后,SuperSocket Server就將該連接視為一個Session,它代表了客戶端與Server端的邏輯連接,所有基於連接的操作都在Session中進行處理,比如收發數據、開關連接等;
-
從二進制數據流到RequestInfo對象: 在SuperSocket中定義了兩種對象,一種表示用戶請求內容的RequestInfo實體類,每個來自客戶端的請求都應該必須實例化成RequestInfo類型。但是網絡中的二進制數據流如何映射成實體類呢?這就是Receive Filter的工作,將接收到的二進制數據轉換成請求實例(RequestInfo),也就是在SuperSocket中通過Receive Filter進行協議解析,將數據流分割成一個個請求的實例對象。如果要實現自定義的協議很明顯需要實現這兩個東西,強悍的是SuperSocket已經內置了諸如結束符協議、固定數量分隔符協議、頭部格式固定並且包含內容長度的協議等通用協議,對於我的項目已經綽綽有余了。
-
從RequestInfo對象到響應服務: SuperSocket將服務抽象成一個個Command,其提供服務的方式也就是根據RequestInfo去執行響應的Command,然后再通過session將數據發送給客戶端。由此可見,每一個Command必須包含兩個東西那就是Session與RequestInfo。通過這種封裝方式,很清晰的划分了各種職責邊界,使得開發起來很舒服、很高效,更難能可貴的是測試很便捷。
-
統管全局的AppServer對象: 前面分析了一個請求從發出到響應的整個流程,整個邏輯連接被視為一個AppSession,而AppServer就是管理Session對象的大Boss,是整個游戲的操控者。諸如Server的啟動關閉,Session連接的管理(注冊、注銷、查詢等),Receive Filter創建工廠的選擇都是AppServer來實現的。總而言之一句話,這是AppServer的世界它做主。
SuperSocket的初步嘗試
如果明白了上述流程,那么使用SuperSocket來開發就很簡單了,再次梳理下相關的數據結構:
-
AppServer:選擇管理的Session類型、選擇Server能夠接受的RequestInfo請求實體類型、選擇將二進制字節流轉換成RequestInfo實體對象的Receive Filter的構建工廠,有了這些基本內容,Server就可以工作了;
-
AppSesssion:Session只和數據流打交道,因此只需要選擇相應的RequestInfo類型就可以,因為Session是運行在AppServer中的,所以此處的RequestInfo必須和AppServer選擇的一致;
-
RecieveFilter:它用來將二進制流轉換成相應的RequestInfo對象實體,說白了也就是協議解析,因此它需要選擇RequestInfo對象類型,然后實現ResolveRequestInfo的功能即可;
-
Command:Server提供服務的方式,首先它需要通過Session與客戶端進行交流,而交流的語言就是網絡協議,也就是RequestInfo類型。
上述幾個東西就是基於SuperSocket進行開發的核心所在,我說的選擇其實就是指定泛型的具體類型。這樣一來,如果我們需要完成一個自定義協議的socket Server,只需要按部就班的實現各個類型就OK了。