高效能 Socket 元件 HP-Socket v3.2.1-RC1 公佈
HP-Socket 是一套通用的高效能 TCP/UDP Socket 元件。包括服務端元件、client元件和 Agent 元件。廣泛適用於各種不同應用場景的 TCP/UDP 通訊系統。提供 C/C++、C#、Delphi、E、Java 等程式語言開發介面。
HP-Socket 對通訊層實現全然封裝,上層應用不必關注通訊層的不論什麼細節。HP-Socket 提供基於事件通知模型的 API 介面。能很easy高效地整合到新舊應用程式中。為了讓使用者能方便高速地學習和使用 HP-Socket,迅速掌握元件的設計思想和用法,特此精心製作了大量 Demo 演示樣例,包括 PUSH 模型演示樣例、PULL模型演示樣例和效能測試演示樣例等。HP-Socket 眼下執行在 Windows 平臺,將來會實現跨平臺支援。
----------------------------------------------------------------
通用性
- 通訊元件的唯一職責就是接受和傳送位元組流,絕對不能參與上層協議解析等工作。
- 與上層使用者解耦、互不依賴,元件與使用者通過操作介面和監聽器介面進行互動,元件實現操作介面為上層提供操作方法;使用者實現監聽器介面把自己註冊為元件的 Listener。接收元件通知。因此,不論什麼使用者僅僅要實現了監聽器介面都能夠使用元件;還有一方面。甚至能夠自己又一次寫一個實現方式全然不同的元件實現給使用者呼叫,僅僅要該元件遵從元件的操作介面,這也是 DIP 設計原則的體現。
可用性
可用性對全部通用元件都是至關重要的。假設太難用還不如自己重頭寫一個來得方便。因此。元件的操作介面和監聽器介面設計得儘量簡單易用(通俗來說就是“傻瓜化”),這兩個介面的主要方法均不超過 5 個。
另外。元件全然封裝了全部的底層 Socket 通訊。上層應用看不到不論什麼通訊細節,不必也不能干預不論什麼通訊操作,Socket 連線被抽象為 Connection ID。該引數作為連線標識提供給上層應用識別不同的連線。
高效能
作為底層的通用元件。效能問題是必須考慮的,絕對不能成為系統的瓶頸。而還有一方面,從實際出發,依據client元件與服務端元件的效能要求採用不同的 Socket 模型。
元件在設計上充分考慮了效能、現實使用情景、可用性和實現複雜性等因素,確保滿足效能要求的同一時候又不會寫得太複雜。做出下面兩點設計決策:
- client:在單獨執行緒中實現 Socket 通訊互動。這樣能夠避免與主執行緒或其他執行緒相互干擾。I/O 模型選擇 Event Select 通訊模型。每一個元件物件管理一個 Socket 連線。
- 服務端:採用高效的 IOCP 通訊模型;利用快取池技術。在通訊的過程中,通常須要頻繁的申請和釋放記憶體緩衝區,建立了動態快取池, 僅僅有當快取池中沒有可用物件時才建立新物件。而當快取物件過多時則會壓縮快取池;另外,元件的動態記憶體通過私有堆(Private Heap)機制分配。避免與 new / malloc 競爭同一時候又降低記憶體空洞。
- Agent:對於代理server或中轉server等應用場景,server自身也作為client向其他server發起大規模連線,一個 Agent 元件物件管理多個 Socket 連線,與服務端採用同樣的技術架構。能夠用作代理server或中轉server的client部件。
伸縮性
能夠依據實際的使用環境要求設定元件的各項效能引數(如:工作執行緒的數量、各種快取池的大小、收發緩衝區的大小、Socket 監聽佇列的大小、Accep 派發的數目以及心跳檢查的間隔等)。
*** v3.2.1 更新 ***
> 新增 TcpAgent / TcpPullAgent 通訊元件:
------------------ 對於代理server或中轉server等應用場景,server自身也作為client向其他server發起大規模連線
- TcpClient / TcpPullClient 基於 Event Select 通訊模型,每一個元件物件管理一個 Socket,並開啟一個執行緒,不適合上述應用場景
- TcpAgent / TcpPullAgent 基於 IOCP 通訊模型。一個元件物件管理多個 Socket,適合用作代理server或中轉server的client通訊元件
- TcpAgent / TcpPullAgent 的使用方式依舊簡單,提供下面介面方法:
/* 1) 通知介面方法 */ OnPrepareConnect(CONNID dwConnID, SOCKET socket) OnConnect(CONNID dwConnID) OnSend(CONNID dwConnID, const BYTE* pData, int iLength) OnReceive(CONNID dwConnID, const BYTE* pData, int iLength) //(Push 模型) OnReceive(CONNID dwConnID, int iLength) //(Pull 模型) OnClose(CONNID dwConnID) OnError(CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) OnAgentShutdown() /* 2) 主要操作方法 */ Start(LPCTSTR pszBindAddress = nullptr, BOOL bAsyncConnect = TRUE) Stop() Connect(LPCTSTR pszRemoteAddress, USHORT usPort, CONNID* pdwConnID = nullptr) Send(CONNID dwConnID, const BYTE* pBuffer, int iLength) Disconnect(CONNID dwConnID, BOOL bForce = TRUE) Fetch(CONNID dwConnID, BYTE* pData, int iLength) //(Pull 模型)
- 新增 TcpAgent / TcpPullAgent 使用演示樣例:Agent-PFM / Agent-Pull / Agent-4C
> 新增 HPSocket for Java SDK:
------------------ 提供 Java 開發包:hpsocket-3.2.1.jar(通過 JNA 實現,眼下僅僅支援 Windows 平臺)
- 執行環境:JDK 1.6+,JVM 執行在 server 模式("java -server"。在 client 模式下某些回撥函式不能正常觸發)
- 新增演示樣例project TestEcho-4J,展示 HPSocket4J 的用法(包括 PULL 模型演示樣例和效能測試演示樣例)
- MBCS 和 Unicode 版本號分佈位於包 org.jessma.hpsocket.mbcs 和 org.jessma.hpsocket.unicode
- HPSocket for Java SDK 提供下面通訊元件:
1) TcpServer:TCP 通訊服務端元件,支援 PUSH/PULL 模型 2) TcpClient:TCP 通訊client元件,支援 PUSH/PULL 模型 3) TcpAgent :TCP 通訊 Agent 元件。支援 PUSH/PULL 模型 4) UdpServer:UDP 通訊服務端元件,支援 PUSH 模型 5) UdpClient:UDP 通訊client元件,支援 PUSH 模型
- HPSocket4J 的用法(以 TcpAgent 為例):
/* 0: 應用程式新增 hpsocket-3.2.1.jar 和 jna-4.1.0.jar */ /* 1: 建立通訊元件物件 */ TcpAgent agent = TcpAgent.create(Mode.PUSH); /* 2: 設定回撥函式物件 */ // (可選) agent.setCallBackOnPrepareConnect(new OnPrepareConnectImpl()); // (可選) agent.setCallBackOnConnect(new OnConnectImpl()); // (必須)PUSH 模型須要設定 OnReceive 回撥函式物件 agent.setCallBackOnReceive(new OnReceiveImpl()); // (必須)PULL 模型須要設定 OnPullReceive 回撥函式物件 // agent.setCallBackOnPullReceive(new OnPullReceiveImpl()); // (可選) agent.setCallBackOnSend(new OnSendImpl()); // (必須) agent.setCallBackOnClose(new OnCloseImpl()); // (必須) agent.setCallBackOnError(new OnErrorImpl()); // (可選) agent.setCallBackOnAgentShutdown(new OnAgentShutdownImpl()); /* 3:啟動通訊元件 */ agent.start("127.0.0.1", false); /* 4:連線server */ agent.connect("localhost", (short)5555, pdwConnID); /* 5:處理通訊資料 */ // 響應 OnReceive / OnPullReceive 事件接收資料 // 使用 agent.send(dwConnID, data, data.length) 傳送資料 /* 6:關閉通訊元件 */ agent.stop(); /* 7:銷燬通訊元件 */ TcpAgent.destroy(agent);
> 其他更新:
------------------ IServer 的 GetClientAddress() 方法改名為 GetRemoteAddress()
- EnServerError / EnClientError 列舉型別合併為 EnSocketError
- EnSocketError / EnHandleResult / EnFetchResult 列舉型別從原所在類中移到外部
- 公共程式碼包 vc-common-src 更新為 v2.3.3(參考:vc-common-src v2.3.3 的 Change Log)
- 新增 HPSocket for C# SDK(由 int 2e 提供)
- 程式碼整理優化
> 升級說明:
------------------ HP-Socket v3.2.1 在功能上相容 HP-Socket v3.1.3 及曾經版本號
- 因為程式碼作了一些重構。須要依據提示改動程式程式碼
- EnServerError / EnClientError 列舉型別合併為 EnSocketError,注意一些列舉值發生了變化
- 不須要使用 TcpAgent / TcpPullAgent 的使用者能夠暫不更新
*** v3.1.3 更新 ***
> 新增其他語言 Demo:
------------------ C#
- Delphi
- E 語言
> Bug Fix:
------------------ 修復 IP 地址推斷錯誤 Bug
1) client連線server時,假設server IP 地址滿位(12個數字:‘AAA.BBB.CCC.DDD’),IP 地址解析錯誤 2) 影響元件:全部 TCP/UDP client元件 3) 影響版本號:v3.1.2 及之前全部版本號
- 修復域名或主機名的 IP 地址解析錯誤 Bug
1) client元件通過域名或主機名連線server時,可能會解析到錯誤的 IP 地址 2) 影響元件:全部 TCP/UDP client元件 3) 影響版本號:v3.1.2 及之前全部版本號
*** 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 為client元件
- 服務端元件 CUdpServer 採用 IOCP 通訊模型
- client元件 CUdpClient 採用 Event Select 通訊模型
- UDP 通訊元件的介面與原 TCP 通訊元件一致,簡單有用
- UDP 通訊元件內建通訊線路自己主動監測機制
- 新增 UDP 通訊元件演示樣例project TestEcho-UDP
> 程式碼重構與優化:
-----------------
- 規範全部介面、類以及程式碼檔案的命名
- 重構和優化了大量元件程式碼
- 服務端元件新增讀寫鎖機制,有效平衡處理效能與安全性
- 服務端元件的 Socket 物件快取列表設定了鎖定時間,提高訪問的安全性