描述C#異步Socket
幾天前在博問中看到一個C#異步Socket問題,就想到筆者2004年做的一個省級交通流量接收服務器項目,當時的基本求如下:
接收自動觀測設備通過無線網卡、Internet和Socket上報的交通量數(shù)據(jù)包 全年365*24運行的自動觀測設備5分鐘上報一次觀測數(shù)據(jù),每筆記錄約2K大小 規(guī)劃全省將有100個左右的自動觀測設備(截止2008年10月還只有30個)
當時,VS2003才發(fā)布年多,筆者也是接觸C#不久。于是Google了國內國外網,希望找點應用C#解決Socket通信問題的思路和代碼。***,找到了兩篇幫助***的文章:一篇是國人寫的Socket接收器框架,應用了獨立的客戶端Socket會話(Session)概念,給筆者提供了一個接收服務器的總體框架思路;另一篇是美國人寫的,提出了多線程、分段接收數(shù)據(jù)包的技術方案,描述了多線程、C#異步Socket的許多實現(xiàn)細節(jié),該文堅定了筆者采用多線程和處理異步Socket接收器的技術路線。
具體實現(xiàn)和測試時筆者還發(fā)現(xiàn),在Internet環(huán)境下的Socket應用中,需要系統(tǒng)有極強的容錯能力:沒有辦法控制異常,就必須允許它們存在(附加源代碼中可以看到,try{}catch{}語句較多)。對此,筆者設計了一個專門的檢查和清理線程,完成無效或超時會話的清除和資源釋放工作。
依稀記得,國內框架作者的名稱空間有ibm,認為是IBM公司職員,通過郵件后才知道其人在深圳。筆者向他請教了幾個問題,相互探討了幾個技術關鍵點。可惜,現(xiàn)在再去找,已經查不到原文和郵件了。只好借此機會,將本文獻給這兩個素未謀面的技術高人和同行,也盼望拙文或源碼能給讀者一點有用的啟發(fā)和幫助。
1、主要技術思路
整個系統(tǒng)由三個核心線程組成,并由.NET線程池統(tǒng)一管理:
偵聽客戶端連接請求線程:ListenClientRequest(),循環(huán)偵聽客戶端連接請求。如果有,檢測該客戶端IP,看是否是同一觀測設備,然后建立一個客戶端TSession對象,并通過異步Socket調用方法BeginReceive()接收數(shù)據(jù)包、EndReceive()處理數(shù)據(jù)包 數(shù)據(jù)包處理線程:HandleDatagrams(),循環(huán)檢測數(shù)據(jù)包隊列_datagramQueue,完成數(shù)據(jù)包解析、判斷類型、存儲等工作 客戶端狀態(tài)檢測線程:CheckClientState(),循環(huán)檢查客戶端會話表_sessionTable,判斷會話對象是否有效,設置超時會話關閉標志,清楚無效會話對象及釋放其資源。
2、主要類簡介
系統(tǒng)主要由3個類組成:
TDatagramReceiver(數(shù)據(jù)包接收服務器):系統(tǒng)的核心進程類,建立Socket連接、處理與存儲數(shù)據(jù)包、清理系統(tǒng)資源,該類提供全部的public屬性和方法 TSession(客戶端會話):由每個客戶端的Socket對象組成,有自己的數(shù)據(jù)緩沖區(qū),清理線程根據(jù)該對象的最近會話時間判斷是否超時 TDatagram(數(shù)據(jù)包類):判斷數(shù)據(jù)包類別、解析數(shù)據(jù)包
3、關鍵函數(shù)和代碼
下面簡介核心類TDatagramReceiver的關鍵實現(xiàn)代碼。系統(tǒng)啟動
系統(tǒng)啟動方法StartReceiver()首先清理資源、創(chuàng)建數(shù)據(jù)庫連接、初始化若干計數(shù)值,然后創(chuàng)建服務器端偵聽Socket對象,***調用靜態(tài)方法ThreadPool.QueueUserWorkItem()在線程池中創(chuàng)建3個核心處理線程。以上介紹C#異步Socket
- Code
- ///
- ///啟動接收器
- ///
- publicboolStartReceiver()
- {
- try
- {
- _stopReceiver=true;
- this.Close();
- if(!this.ConnectDatabase())returnfalse;
- _clientCount=0;
- _datagramQueueCount=0;
- _datagramCount=0;
- _errorDatagramCount=0;
- _exceptionCount=0;
- _sessionTable=newHashtable(_maxAllowClientCount);
- _datagramQueue=newQueue<TDatagram>(_maxAllowDat)
【編輯推薦】