HP-Socket 是一套通用的高性能 Windows Socket 組件,提供服務端組件(IOCP 模型)和客戶端組件(Event Select 模型),廣泛適用於 Windows 平臺的 TCP/UDP 通信系統。HP-Socket 對通信層實現完全封裝,上層應用不必關注通信層的任何細節;HP-Socket 提供基於事件通知模型的 API 接口,能非常簡單高效地整合到各類應用程序中;另外,爲了讓大家能更方便的學習 HP-Socket,特此精心製作了功能測試示例(Test Echo)、性能測試示例(Test Echo-PFM)、PULL 模型測試示例(Test Echo-Pull) 和 UDP 測試示例(Test Echo-UDP),用戶可以通過這幾個測試示例入手,迅速掌握組件的設計思想和使用方法。
----------------------------------------------------------------
通用性
通信組件的唯一職責就是接受和發送字節流,絕對不能參與上層協議解析等工作;
與上層使用者解耦、互不依賴,組件與使用者通過操作接口和監聽器接口進行交互,組件實現操作接口爲上層提供操作方法;使用者實現監聽器接口把自己註冊爲組件的 Listener,接收組件通知。因此,任何使用者只要實現了監聽器接口都可以使用組件;另一方面,甚至可以自己重新寫一個實現方式完全不同的組件實現給使用者調用,只要該組件遵從組件的操作接口,這也是 DIP 設計原則的體現。
可用性
可用性對所有通用組件都是至關重要的,如果太難用還不如自己重頭寫一個來得方便。因此,組件的操作接口和監聽器接口設計得儘量簡單易用(通俗來說就是“傻瓜化”),這兩個接口的主要方法均不超過 5 個。另外,組件完全封裝了所有的底層 Socket 通信,上層應用看不到任何通信細節,不必也不能干預任何通信操作,Socket 連接被抽象爲 Connection ID,該參數作爲連接標識提供給上層應用識別不同的連接。
高性能
作爲底層的通用組件,性能問題是必須考慮的,絕對不能成爲系統的瓶頸。而另一方面,從實際出發,根據客戶端組件與服務端組件的性能要求採用不同的 Socket 模型。組件在設計上充分考慮了性能、現實使用情景、可用性和實現複雜性等因素,確保滿足性能要求的同時又不會寫得太複雜。做出以下兩點設計決策:
客戶端:在單獨線程中實現 Socket 通信交互。這樣可以避免與主線程或其他線程相互干擾;I/O 模型選擇 Event Select 通信模型。
服務端:採用 Windows 平臺效率最高的 IOCP 通信模型;利用緩存池技術,在通信的過程中,通常需要頻繁的申請和釋放內存緩衝區,建立了動態緩存池, 只有當緩存池中沒有可用對象時才創建新對象,而當緩存對象過多時則會壓縮緩存池;另外,組件的動態內存通過私有堆(Private Heap)機制分配,避免與 new / malloc 競爭同時又減少內存空洞。
伸縮性
可以根據實際的使用環境要求設置組件的各項性能參數(如:工作線程的數量、各種緩存池的大小、收發緩衝區的大小、Socket 監聽隊列的大小、Accep 派發的數目以及心跳檢查的間隔等)。
*** v3.1.3 更新 ***
> 增加其它語言 Demo:
-----------------C#
Delphi
E 語言
> Bug Fix:
-----------------修復 IP 地址判斷錯誤 Bug
1) 客戶端連接服務器時,如果服務器 IP 地址滿位(12個數字:‘AAA.BBB.CCC.DDD’),IP 地址解析錯誤 2) 影響組件:所有 TCP/UDP 客戶端組件 3) 影響版本:v3.1.2 及之前所有版本
修復域名或主機名的 IP 地址解析錯誤 Bug
1) 客戶端組件通過域名或主機名連接服務器時,可能會解析到錯誤的 IP 地址 2) 影響組件:所有 TCP/UDP 客戶端組件 3) 影響版本:v3.1.2 及之前所有版本
> 升級說明:
-----------------使用 HP-Socket v3.1.2 及以前版本的應用程序可以安全升級到 HP-Socket v3.1.3
*** v3.1.2 更新 ***
> 修改 Server 組件的 OnClose() / OnError() 事件的觸發規則:
-----------------以前版本的 TCP/UDP Server 組件中,當關閉一個連接時可能會同時觸發一個 OnClose() 事件和若干個 OnError() 事件
由於存在上述可能性,所以應用程序需要對 OnClose() / OnError() 的處理事件代碼段進行同步
從 v3.1.2 開始,當多個 OnClose() / OnError() 事件同時發生時,組件只會嚮應用程序通知第一個事件,後續事件則忽略
因此,應用程序在處理 OnClose() / OnError() 事件時不必處理同步,減少了出錯的可能和編寫同步及檢測代碼的負擔
示例代碼
/* 示例代碼一:*/ /*----------------------------------------------------------------------------*/ ISocketListener::EnHandleResult CServerDlg::OnClose(CONNID dwConnID) { // 以前版本:有可能存在併發的 OnClose()/OnError(),要把代碼放在臨界區中並檢測返回值 CCriSecLock locallock(m_csPkgInfo); // <-- 臨界區 PVOID pInfo = nullptr; // <-- 檢測返回值 if(m_Server->GetConnectionExtra(dwConnID, &pInfo) && pInfo != nullptr) { m_Server->SetConnectionExtra(dwConnID, nullptr); delete pInfo; } } /* 示例代碼二:*/ /*----------------------------------------------------------------------------*/ ISocketListener::EnHandleResult CServerDlg::OnClose(CONNID dwConnID) { // v3.1.2 版本:只會接收到一個 OnClose()/OnError() 事件,能安全地移除臨界區代碼和檢測代碼 PVOID pInfo = nullptr; m_Server->GetConnectionExtra(dwConnID, &pInfo); ASSERT(pInfo != nullptr); delete pInfo; }
*** v3.1.1 更新 ***
> 增加導出純 C 函數的動態鏈接庫 HPSocket4C.dll:
-----------------增加代碼文件 HPSocket4C.h 和 HPSocket4C.cpp,用於創建 HPSocket4C.dll
導出純 C 函數,讓其它語言(如:C/C#/Delphi 等)能方便地使用 HPSocket
HPSocket4C.dll 使用方法
方法一: ------------------------------------------------------------------------------ (0) (C/C++ 程序)包含 HPSocket4C.h 頭文件 (1) 調用 ::Create_HP_XxxListener() 函數創建監聽器對象 (2) 調用 ::Create_HP_Xxx(pListener) 函數創建 HPSocket 對象 (3) 調用 ::HP_Set_FN_Xxx_OnYyy(pListener, ...) 函數設置監聽器的回調函數 (4) 調用相關導出函數操作 HPSocket 對象 (5) ...... ...... (6) 調用 ::Destroy_HP_Xxx(pSocket) 函數銷燬 HPSocket 對象 (7) 調用 ::Destroy_HP_XxxListener(pListener) 函數銷燬監聽器對象 方法二: ------------------------------------------------------------------------------ (1) 應用程序把需要用到的導出函數封裝到特定語言的包裝類中 (2) 通過包裝類封裝後,以面向對象的方式使用 HPSocket
動態鏈接庫發行版本
(1) x86/HPSocket4C.dll - (32位/MBCS/Release) (2) x86/HPSocket4C_D.dll - (32位/MBCS/DeBug) (3) x86/HPSocket4C_U.dll - (32位/UNICODE/Release) (4) x86/HPSocket4C_UD.dll - (32位/UNICODE/DeBug) (5) x64/HPSocket4C.dll - (64位/MBCS/Release) (6) x64/HPSocket4C_D.dll - (64位/MBCS/DeBug) (7) x64/HPSocket4C_U.dll - (64位/UNICODE/Release) (8) x64/HPSocket4C_UD.dll - (64位/UNICODE/DeBug)
> 全面啓用 Buffer Pool 緩存機制:
-----------------Common/Src 增加代碼文件 bufferpool.h 和 bufferpool.cpp,實現 Buffer Pool 緩存機制
通過 Buffer Pool 緩存機制提升內存使用效率,減少動態內存分配和釋放操作,避免內存空洞
ICTcpClient 用 CItemPool 和 TItemList 實現發送緩衝區
CUdpClient 用 CItemPool 和 TItemList 實現發送緩衝區
CTcpPullClient 用 CItemPool 和 TItemList 實現發送緩衝區和 PULL 緩衝區
CTcpPullServer 用 CBufferPool 和 TBuffer 實現 PULL 緩衝區
*** v3.0.2 更新 ***
> 把 HP-Socket 編譯爲動態鏈接庫:
-----------------
應用程序可以通過導入源代碼或動態鏈接庫方式使用 HP-Socket
動態鏈接庫使用方法
方法一: ------------------------------------------------------------------------------ (0) 應用程序包含 SocketInterface.h 和 HPSocket.h 頭文件 (1) 調用 HP_Create_Xxx() 函數創建 HPSocket 對象 (2) 使用完畢後調用 HP_Destroy_Xxx() 函數銷燬 HPSocket 對象 方法二: ------------------------------------------------------------------------------ (0) 應用程序包含 SocketInterface.h 和 HPSocket.h 頭文件 (1) 創建 CXxxWrapper 包裝器,通過包裝器智能指針使用 HPSocket 對象
動態鏈接庫發行版本
(1) x86/HPSocket.dll - (32位/MBCS/Release) (2) x86/HPSocket_D.dll - (32位/MBCS/DeBug) (3) x86/HPSocket_U.dll - (32位/UNICODE/Release) (4) x86/HPSocket_UD.dll - (32位/UNICODE/DeBug) (5) x64/HPSocket.dll - (64位/MBCS/Release) (6) x64/HPSocket_D.dll - (64位/MBCS/DeBug) (7) x64/HPSocket_U.dll - (64位/UNICODE/Release) (8) x64/HPSocket_UD.dll - (64位/UNICODE/DeBug)
*** v3.0.1 更新 ***
> 新增 UDP 通信組件:
-----------------
新增兩個 UDP 通信組件:CUdpServer 爲服務端組件,CUdpClient 爲客戶端組件
服務端組件 CUdpServer 採用 IOCP 通信模型
客戶端組件 CUdpClient 採用 Event Select 通信模型
UDP 通信組件的接口與原 TCP 通信組件一致,簡單實用
UDP 通信組件內置通信線路自動監測機制
新增 UDP 通信組件示例工程 TestEcho-UDP
> 代碼重構與優化:
-----------------
規範所有接口、類以及代碼文件的命名
重構和優化了大量組件代碼
服務端組件加入讀寫鎖機制,有效平衡處理性能與安全性
服務端組件的 Socket 對象緩存列表設置了鎖定時間,提高訪問的安全性
*** v2.2.3 更新 ***
> 連接 ID 的數據類型改爲 ‘CONNID’:
-----------------
在SocketHelper.h 中定義 CONNID 數據類型(默認:typedef ULONG_PTR CONNID)
應用程序可以把 CONNID 定義爲其希望的類型(如:ULONG / ULONGLONG 等)
爲了便於移植與維護,應用程序的任何地方都應該用‘CONNID’類型引用連接 ID
> 服務端 Socket 組件支持爲每個連接綁定附加數據:
-----------------
IServerSocket 和 CIocpServer 增加方法 Get/SetConnectionExtra()
通過上述兩個方法,應用程序可以爲每個連接綁定任意附加數據並把數據獲取出來
*** v2.2.2 更新 ***
> 優化心跳檢測相關功能:
-----------------
IServerSocket 和 IClientSocket 的 Get/SetKeepAliveTimes() 方法改爲 Get/SetKeepAliveTime()
CIocpServer 和 CClientSocket 的默認 KeepAliveTime 屬性改爲 5000
CIocpServer 和 CClientSocket 的默認 KeepAliveInterval 屬性改爲 3000
*** v2.2.1 更新 ***
> PULL 模型支持:
-----------------
ISocketListener 增加 PULL 模型數據接收通知方法 OnReceive(dwConnID, int)
增加 PULL Socket 接口 IPullSocket,該接口的 Fetch(dwConnID, pBuffer, iLength) 方法用於抓取通信數據
> Server:
-----------------
服務端 Socket 接口 ISocketServer 改名爲 IServerSocket
增加 PULL Server Socket 監聽器抽象類 CPullServerSocketListener
增加 PULL Server Socket 接口 IPullServerSocket
增加 PULL Server Socket 實現類 CIocpPullServer
> Client:
-----------------
客戶端 Socket 接口 ISocketClient 改名爲 IClientSocket
客戶端 Socket 實現類 CSocketClient 改名爲 CClientSocket
增加 PULL Client Socket 監聽器抽象類 CPullClientSocketListener
增加 PULL Client Socket 接口 IPullClientSocket
增加 PULL Client Socket 實現類 CPullClientSocket