TCP/UDP簡易通訊框架原始碼,支援輕鬆管理多個TCP服務端(客戶端)、UDP客戶端

周見智發表於2015-07-22

目錄

說明

之前有好幾篇部落格在講TCP/UDP通訊方面的內容,也有做過一些Demo(包括整理出來的、可供學習使用的簡單通訊框架)。具體可以參見以下部落格:

http://www.cnblogs.com/xiaozhi_5638/p/4244797.html(清晰易懂TCP通訊原理解析)

http://www.cnblogs.com/xiaozhi_5638/p/3290283.html(基於泵的TCP通訊過程建立)

http://www.cnblogs.com/xiaozhi_5638/p/3169641.html(基於泵的UDP通訊過程建立)

http://www.cnblogs.com/xiaozhi_5638/p/4528551.html(泵結構在系統中的作用)

可以看出,很多部落格一直在強調“泵”(迴圈結構)在各個場合中的作用,若有不清楚泵結構的朋友,可以參見這篇部落格“程式碼中的泵”。今天這次部落格的重點並不是講泵結構在通訊過程中的應用,而是講如何在同一程式中輕鬆快捷地建立多個TCP服務端(繫結多個Port)、多個TCP客戶端(隨意連線指定服務端)、多個UDP客戶端(繫結多個Port),同時能夠進行統一管理、訪問。

在TCP通訊開發過程中,經常會出現一個程式需要監聽多個Port,或者一個程式需要連線多個TCP伺服器(本人實際專案中遇到過),那麼如何統一、方便管理建立的多個Socket呢?

如上圖左邊所示,一個程式需要同時訪問兩個Server,那麼它至少要同時保持兩個Socket連線。同理,一個服務程式很可能同時監聽多個Port,需要管理多個偵聽Socket。在UDP通訊系統中(上圖右邊),一個程式也可能需要監聽多個Port,同時接收多個Port上的資料。那麼本文提供了一套可以輕鬆管理這些多個Socket的方案。

 

TCP/UDP通訊主要結構

TCP服務端

一個TCP服務端主要包含兩個結構:一個是Socket偵聽迴圈(Socket偵聽泵),一個便是資料接收迴圈(資料接收泵)。前者主要負責處理Socket連入請求,後者負責接收對應客戶端發來的資料。下圖顯示的是一個TCP服務端包含的主要構造:

TCP客戶端

一個TCP客戶端主要包含一個結構:資料接收迴圈(資料接收泵)。客戶端Socket連入伺服器成功後,便需要開啟資料接收迴圈,用於接收服務端發來的資料。下圖顯示的是一個TCP客戶端包含的主要構造:

UDP客戶端

一個UDP客戶端主要包含一個結構:資料接收迴圈(資料接收泵)。客戶端繫結本地Port成功後,便需要開啟資料接收迴圈,用於接收來自繫結埠的資料。下圖顯示的是一個UDP客戶端包含的主要構造:

注:

雖然UDP通訊中的每個終端都是平等的(不存在主動連入和被動連入),但還是習慣上稱每個終端為Client。雖然它包含的主要結構和TCP客戶端類似(都只有一個資料接收迴圈),但是在TCP中,客戶端Socket需要提前Connect到伺服器,而通常情況下,UDP需要提前繫結本地埠。

 

管理多個Socket的解決方案

這裡說到的Socket,在TCP服務端中指的是偵聽Socket,在TCP客戶端中指的是與服務端建立連線的Socket,而在UDP客戶端中指的是繫結本地埠的Socket。這些Socket都可以存在多個,TCP服務端中可以有多個Socket偵聽不同的Port,TCP客戶端可以有多個Socket與不同的服務端建立連線,而UDP客戶端中則可以有多個Socket繫結不同的埠。那麼如何管理多個Socket呢?

答案其實很簡單,可以將它們放進一個容器,統一透過容器管理、訪問。那麼怎樣區分不同的Socket呢?我們可以給每個Socket加一個唯一標示(ID)。之後每次訪問,均透過ID區分,只要給定ID,其餘的操作均相同。這樣一來,TCP服務端、TCP客戶端以及UDP客戶端的構造可以變成:

多個TCPServer:

多個TCPClient

多個UDPClient

每次訪問,比如TCP服務端開啟偵聽、註冊事件以及主動呼叫傳送資料的API時,均可以透過容器代理進行操作,只需要給出指定的ID進行區分即可。

 

框架中TCP部分的用法

TCP服務端

框架公開了TCPServerManager、TCPEndPoint兩個型別,前者主要負責代理操作的功能,所有對服務端的操作均透過它來完成;後者對應每個連線進來的客戶端。

1)建立伺服器

之後便可以使用manager操作建立好的伺服器。注意如果這裡已經存在ID為RegisterServer的伺服器的話,manager就指代已經建立好的伺服器。我們還可以建立第二伺服器:

以上,只要給定的ID不同即可。

2)啟動伺服器

3)註冊事件

以上分別註冊客戶端連線、斷開以及傳送訊息的事件,之後便可以在事件處理方法中處理訊息。

4)訊息處理

當客戶端傳送訊息時,系統會激發TCPMessageReceived事件,我們在事件處理程式中可以解析、處理訊息:

在訊息處理這塊,框架簡單地定義了一個“協議”:訊息型別+訊息正文。如果你覺得不夠,完全可以在args.Data中再定義自己的協議。客戶端上線、下線處理方式類似。這裡不再贅述。

TCP客戶端

框架公開了TCPClientManager型別,它主要負責代理操作的功能,所有對客戶端的操作均透過它來完成。

1)建立客戶端

以上建立了一個TCP客戶端。如果給定的ID已存在,那麼manager指代已經存在的客戶端。同理,我們可以建立第二個客戶端:

以上,只要給定的ID不同即可。

2)連線伺服器

3)註冊事件

以上註冊訊息事件,當收到服務端訊息時會激發TCPMessageReceived事件。

4)訊息處理

TCP客戶端訊息處理這塊參見TCP服務端。原理類似。

 

框架中UDP部分的用法

UDP客戶端

框架公開了UDPClientManager型別,主要負責代理操作的功能,對UDP客戶端的所有操作均由它來完成。

1)建立客戶端

以上建立了一個UDP客戶端。如果給定的ID已存在,那麼manager指代的是已經存在的UDP客戶端。同理,我們可以建立第二個UDP客戶端:

以上,只要給定的ID不存在即可。

2)監聽埠

以上建立了兩個不同的UDP客戶端,分別監聽不同的Port,接收不同的資料。

3)註冊事件

以上註冊了訊息事件,當埠上有資料收到時會激發UDPMessageReceived事件。

4)訊息處理

當UDP客戶但收到訊息時,系統會激發UDPMessageReceived事件,我們可以在事件處理程式中解析、處理訊息:

注意UDP這塊處理訊息有一點與TCP不同,args引數中是以RemoteIP和RemotePort來表明訊息傳送方的資訊,而TCP處理訊息時,args引數中以TCPEndPoint來代表訊息傳送方的資訊,後者包含的資訊更全(不只有RemoteIP和RemotePort,具體參見原始碼)。

在訊息處理這塊,框架簡單地定義了一個“協議”:訊息型別+訊息正文。如果你覺得不夠,完全可以在args.Data中再定義自己的協議。

 

框架原始碼結構

.NET4.0  VS2010

對外公開的有TCPServerManager、TCPClientManager、TCPEndPoint、UDPClientManager以及Msg列舉型別。

 

補充說明

  • TCP部分已解決沾包問題,附帶心跳檢測功能(有待完善);
  • 框架預設採用了一個簡單的協議,用以區分傳送訊息的型別。我們在使用過程中,完全可以自定義應用層協議(再封裝一層),並在收到資料後解析;
  • TCP服務端的線上列表需要自己人工維護(上下線);收到的訊息資料都是byte[]型別,需要自己解析;而且不能註冊自己想要的訊息(必須全部接收)。由於我司主要開發區域網內網系統,對連線數量要求不是很高,我司實際使用中的通訊框架經實體機房測試,連線數在400+,系統執行穩定。TCP部分傳送3G大檔案,不會出現記憶體異常等問題。
  • 這次也是為了驗證多個Socket管理的方案,所以才出了這個框架,由於時間倉促,所以僅供學習使用。若有人要應用到實際專案中去,可能需要修改完善一些地方,因為我並沒有完全測試。

原始碼地址

原始碼中帶有兩個Demo。

github:https://github.com/sherlockchou86/TJSYXYCommunication

rar檔案直接下載:https://files.cnblogs.com/files/xiaozhi_5638/TJSYXY.Communication.rar

相關文章