< type="text/javascript">
(來源:http://blog.csdn.net/hulihui
)
在程序設(shè)計與實(shí)際應(yīng)用中,Socket數(shù)據(jù)包接收服務(wù)器夠得上一個經(jīng)典問題了:需要計算機(jī)與網(wǎng)絡(luò)編程知識(主要是Socket),與業(yè)務(wù)處理邏輯密切
(如:包組成規(guī)則),同時還要兼顧系統(tǒng)運(yùn)行的穩(wěn)定、效率、安全與管理等。具體應(yīng)用時,在滿足業(yè)務(wù)處理邏輯要求的基礎(chǔ)上,存在側(cè)重點(diǎn):有些需要考慮并發(fā)與效
率,有些需要強(qiáng)調(diào)穩(wěn)定與可靠等等。雖然.NET 2.0
Framework上的IOCP(I/O完成端口)異步技術(shù)可以有效解決并發(fā)等問題,但完全的異步模式也缺乏一些控制上的靈活性,例如:Socket暫停
操作等。
本文介紹的是一個傳統(tǒng)Socket數(shù)據(jù)包服務(wù)器解決方案,該方案改自筆者2005年底的一個交通部省級公路交通流量數(shù)據(jù)服務(wù)器中心
(DSC)項目。當(dāng)時.NET Framework 2.0 與 Visual Studio 2005
發(fā)布沒多久,筆者接觸C#的時間不長。于是Google了國內(nèi)國外網(wǎng),希望找點(diǎn)應(yīng)用C#解決Socket通信問題的思路和代碼。最后,找到了兩篇幫助最大
的文章:一篇是國人2005年3月寫的Socket接收器框架——
在C#中使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的C/S的通訊構(gòu)架(一)
(分
(一)、(二)兩篇),該文應(yīng)用了客戶端Socket會話(Session)概念;另一篇是美國人寫的,提出了多線程、分段接收數(shù)據(jù)包的技術(shù)方案,描述了
多線程、異步Socket的許多實(shí)現(xiàn)細(xì)節(jié),該文堅定了筆者采用多線程和異步方式處理Socket接收器的技術(shù)路線。第一個版本EMTASS
1.0(EMTASS,Extensible Multi-Thread Asynchronous Socket
Server)于2006年初完成并投入使用。
今年暑假,筆者修改了原Socket接收服務(wù)器代碼,即EMTASS 1.1。最近,又按框架的可擴(kuò)展性、可重用性等要求重新構(gòu)思和設(shè)計了EMTASS,即EMTASS 2.0。下面的介紹共分六個部分:
- 總體思路與架構(gòu)
- 關(guān)鍵實(shí)現(xiàn)技術(shù)
- 框架使用簡介
- 一般測試結(jié)果
- 總結(jié)與展望
- 版本與源碼
1.1 總體思路
總體構(gòu)思上,主要考慮多線程、異步Socket和可擴(kuò)展性三個方面。
1) 三個核心線程
在Internet環(huán)境下的Socket應(yīng)用中,客戶端和網(wǎng)絡(luò)容易出現(xiàn)異常,此時必須釋放異常退出的Socket資源??紤]到服務(wù)器的高并
發(fā)能力,一般采取包接收和處理分開的策略:將接收到的包添加到包隊列,然后處理隊列中的數(shù)據(jù)包。當(dāng)然,偵聽遠(yuǎn)程客戶端的連接請求可以用Socket的
AcceptAsync()異步方法(IOCP,I/O完成端口由此開始)??紤]到暫停、關(guān)閉同步操作,仍然用一個線程。這樣,清理資源、處理數(shù)據(jù)包、偵
??蛻暨B接請求就是組成了EMTASS架構(gòu)的三個核心線程,它們由.NET線程池統(tǒng)一管理:
-
客戶端連接偵聽線程 StartServerListen():
循環(huán)偵聽遠(yuǎn)程客戶端的Socket連接請求。如果存在,通過適當(dāng)規(guī)范性判斷
后創(chuàng)建該Socket的客戶端會話TSessionBase對象(實(shí)際上是該類的派生類對象),同時調(diào)用該會話對象的Socket異步數(shù)據(jù)接收方法
BeginReceive(),接收到的數(shù)據(jù)包存放在會話對象的包隊列中。當(dāng)然,新增的TSessionBase對象將添加到會話隊列
m_sessionTable(一個Dictionary<>泛型對象)中,該隊列表就是清理和處理線程的遍歷對象;
-
數(shù)據(jù)包處理線程 CheckDatagramQueue():
循環(huán)檢測TSessonBase隊列中的會話對象,調(diào)用該對象的相關(guān)方法完成數(shù)據(jù)包解析、判斷類型、數(shù)據(jù)存儲等任務(wù);
- 會話表檢測線程 CheckSessionTable():
循環(huán)檢查會話表m_sessionTable中的各個會話對象,分步驟清理已經(jīng)超時、無效或異常的會話對象,清理會話對象的緩沖區(qū),釋放其Socket資源。
2) 異步處理模式
.NET
Framework中的Socket具有完整的異步處理能力:偵聽后異步接收(AcceptAsync())、數(shù)據(jù)異步接收
(BeginReceive())、數(shù)據(jù)異步發(fā)送(BeginSend())等。EMTASS框架采取了異步接收和發(fā)送方式,并封裝在
TSessionBase類中。在EMTASS的版本1.0、1.1中,這些方法在主類TSocketServerBase中實(shí)現(xiàn),顯然不符合類封裝原
則。
3) 系統(tǒng)可擴(kuò)展性
可擴(kuò)展性主要考慮不同的業(yè)務(wù)處理邏輯和應(yīng)用場景,即:數(shù)據(jù)包格式、數(shù)據(jù)存儲方法、數(shù)據(jù)庫服務(wù)器等??蚣蹺MTASS的可擴(kuò)展性體現(xiàn)在類的泛型與抽象設(shè)計、方法虛擬和保護(hù)等方面:
- 抽象類:
會話基類TSessionBase、數(shù)據(jù)庫基類TDatabaseBase均是抽象類,分別提供了數(shù)據(jù)包分析與判斷、數(shù)據(jù)存儲的虛擬方法;
- 泛型類:
主要基類TSocketServerBase有TSessionBase、TDatabaseBase兩個泛型約束參數(shù),可以根據(jù)這兩個抽象類的派生類產(chǎn)生具體的服務(wù)器類型;
- 方法抽象(abstract):
TSessionBase的數(shù)據(jù)包分析方法AnalyzeDatagram()、TDatabaseBase的數(shù)據(jù)庫打開方法Open()均是抽象的,必須在派生類中根據(jù)業(yè)務(wù)處理邏輯和數(shù)據(jù)庫類型重寫;
- 方法保護(hù)(protected):
與事件處理有關(guān)的方法、與業(yè)務(wù)處理邏輯相關(guān)的方法全部是protected方法,可以根據(jù)實(shí)際情況重寫。
1.2 類架構(gòu)
1)主要類層次結(jié)構(gòu)
(圖1 主要類層次關(guān)系)
按應(yīng)用類別分,EMTASS主要有四組類:Socket服務(wù)器類、Session會話類、Database數(shù)據(jù)庫類和枚舉類型。
- Socket服務(wù)器類
- 服務(wù)器泛型類 TSocketServerBase:
該類包括了一個服務(wù)器Socket對象、一個TDatabaseBase派生
類對象、一個會話TSessionBase類派生對象的列表(Dictionary<>泛型對象),封裝了TDatabaseBase、
TSessionBase的全部事件,提供統(tǒng)一的對外公開接口和事件;
- 泛型參數(shù):
服務(wù)器基類TSocketServerBase有兩個泛型參數(shù):TSessionBase類和TDatabaseBase類,定制它們的派生類后可以確定泛型類的具體版本。
- 客戶端會話類
- 會話核心成員類 TSessionCoreInfo:
是TSessionBase的基類,包括會話的核心字段:登錄時間、最近會話時間、IP地址、客戶端名、對象狀態(tài)等,是會話列表清單和事件參數(shù)的基類之一。該類的成員字段全部是protected的,需要在派生類中賦予具體值;
- 抽象會話類 TSessionBase:
封裝了客戶端Socket、數(shù)據(jù)接收緩沖區(qū)、數(shù)據(jù)包緩沖區(qū)、數(shù)據(jù)包隊列等數(shù)據(jù)結(jié)構(gòu),包括了與客戶端通信相關(guān)的全部方法:數(shù)據(jù)接收與發(fā)送、數(shù)據(jù)包處理等。
- 數(shù)據(jù)庫類
- 抽象數(shù)據(jù)庫基類 TDatabaseBase:
封裝了數(shù)據(jù)庫打開與關(guān)閉、異常事件處理等方法,其中數(shù)據(jù)連接屬性DbConnection是虛屬性、數(shù)據(jù)庫打開方法Open()是抽象方法,需要在派生類中重寫;
- 基類TSqlServerBase:
派生自TDatabaseBase,應(yīng)用System.Data.SqlClient名稱空間中SqlServer相關(guān)類型重定義了數(shù)據(jù)庫連接屬性DbConnection、重寫了Open()方法;
- 基類TOleDbDatabaseBase:
派生自TDatabaseBase,應(yīng)用System.Data.OleDb名稱空間中OleDb數(shù)據(jù)訪問相關(guān)類型重定義了基類的連接屬性DbConnection、重寫了Open()方法
- 枚舉類型
- 會話狀態(tài)類型 TSessioinState:
取4個值:Valid、Invalid、Shutdown和Closed。為Valid時表示會話是有效的,為Invalid時表示會話將被清理,為Shutdown時表示會話Socket正在卸載,為Closed時表示會話已經(jīng)關(guān)閉、資源已經(jīng)清理;
- 會話斷開類型 TDisconnectType:
取3個值:Normal、Timeout和Exception,分別表示正常連接、超時斷開、異常斷開。其中,超時表示最近兩次會話接收數(shù)據(jù)的時間超過約定的時限,防止某些會話長時間占有資源。
2)事件參數(shù)類型結(jié)構(gòu)圖
(圖2 事件參數(shù)類層次關(guān)系)
EMTASS框架的事件包括三類:第一,普通事件,如:服務(wù)器啟動與停止;第二,異常事件,接收與發(fā)送數(shù)據(jù)異常、數(shù)據(jù)庫連接或數(shù)據(jù)存儲異常
等;第三,與會話相關(guān)事件,如:增加會話對象、接收到一個合法數(shù)據(jù)包等。異常與會話結(jié)合即是會話異常事件。通過泛型委托EventHandler可以定義類事件,其中的事件參數(shù)類型如下:
- 異常事件參數(shù)類 TExceptionEventArgs:
封裝了異常Exception對象的Message值;
- 會話事件參數(shù)類 TSessionEventArgs:
封裝了一個TSessionCoreInfo對象;
- 會話異常參數(shù)類 TSessionExceptionEventArgs:
派生自TSessionEventArgs,包括異常消息字段Message。