HP-Socket 是一套通用的高性能 TCP/UDP Socket 組件,包含服務端組件、客戶端組件和 Agent 組件,普遍適用於各類不一樣應用場景的 TCP/UDP 通訊系統,提供 C/C++、C#、Delphi、E(易語言)、Java、Python 等編程語言接口。HP-Socket 對通訊層實現徹底封裝,上層應用沒必要關注通訊層的任何細節;HP-Socket 提供基於事件通知模型的 API 接口,能很是簡單高效地整合到新舊應用程序中。爲了讓使用者能方便快速地學習和使用 HP-Socket,迅速掌握組件的設計思想和使用方法,特此精心製做了大量 Demo 示例,包括 PUSH 模型示例、PULL模型示例和性能測試示例等。HP-Socket 目前運行在 Windows 平臺,未來會實現跨平臺支持。html
----------------------------------------------------------------java
通用性編程
- 通訊組件的惟一職責就是接受和發送字節流,絕對不能參與上層協議解析等工做。
- 與上層使用者解耦、互不依賴,組件與使用者經過操做接口和監聽器接口進行交互,組件實現操做接口爲上層提供操做方法;使用者實現監聽器接口把本身註冊爲組件的 Listener,接收組件通知。所以,任何使用者只要實現了監聽器接口均可以使用組件;另外一方面,甚至能夠本身從新寫一個實現方式徹底不一樣的組件實現給使用者調用,只要該組件聽從組件的操做接口,這也是 DIP 設計原則的體現。
可用性緩存
可用性對全部通用組件都是相當重要的,若是太難用還不如本身重頭寫一個來得方便。所以,組件的操做接口和監聽器接口設計得儘可能簡單易用(通俗來講就是「傻瓜化」),這兩個接口的主要方法均不超過 5 個。另外,組件徹底封裝了全部的底層 Socket 通訊,上層應用看不到任何通訊細節,沒必要也不能干預任何通訊操做,Socket 鏈接被抽象爲 Connection ID,該參數做爲鏈接標識提供給上層應用識別不一樣的鏈接。安全
高性能服務器
做爲底層的通用組件,性能問題是必須考慮的,絕對不能成爲系統的瓶頸。而另外一方面,從實際出發,根據客戶端組件與服務端組件的性能要求採用不一樣的 Socket 模型。組件在設計上充分考慮了性能、現實使用情景、可用性和實現複雜性等因素,確保知足性能要求的同時又不會寫得太複雜。作出如下兩點設計決策:架構
- 客戶端:在單獨線程中實現 Socket 通訊交互,這樣能夠避免與主線程或其餘線程相互干擾;I/O 模型選擇 Event Select 通訊模型。每一個組件對象管理一個 Socket 鏈接。
- 服務端:採用高效的 IOCP 通訊模型;利用緩存池技術,在通訊的過程當中,一般須要頻繁的申請和釋放內存緩衝區,創建了動態緩存池, 只有當緩存池中沒有可用對象時才建立新對象,而當緩存對象過多時則會壓縮緩存池;另外,組件的動態內存經過私有堆(Private Heap)機制分配,避免與 new / malloc 競爭同時又減小內存空洞。
- Agent:對於代理服務器或中轉服務器等應用場景,服務器自身也做爲客戶端向其它服務器發起大規模鏈接,一個 Agent 組件對象管理多個 Socket 鏈接,與服務端採用相同的技術架構,能夠用做代理服務器或中轉服務器的客戶端部件。
伸縮性併發
能夠根據實際的使用環境要求設置組件的各項性能參數(如:工做線程的數量、各類緩存池的大小、收發緩衝區的大小、Socket 監聽隊列的大小、Accep 派發的數目以及心跳檢查的間隔等)。app
(項目主頁:點擊這裏,下載地址:點擊這裏)socket
*** v3.2.1 更新 ***
> 增長 TcpAgent / TcpPullAgent 通訊組件:
-----------------
- 對於代理服務器或中轉服務器等應用場景,服務器自身也做爲客戶端向其它服務器發起大規模鏈接
- TcpClient / TcpPullClient 基於 Event Select 通訊模型,每一個組件對象管理一個 Socket,並開啓一個線程,不適合上述應用場景
- TcpAgent / TcpPullAgent 基於 IOCP 通訊模型,一個組件對象管理多個 Socket,適合用做代理服務器或中轉服務器的客戶端通訊組件
- 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
- 增長 TcpAgent + TcpServer 實現的 HTTP 代理服務器示例:HttpProxy
> 增長 HPSocket for Java SDK:
-----------------
- 提供 Java 開發包:hpsocket-3.2.1.jar(經過 JNA 實現,目前只支持 Windows 平臺)
- 運行環境:JDK 1.6+,JVM 運行在 server 模式("java -server",在 client 模式下性能受影響)
- MBCS 和 Unicode 版本分佈位於包 org.jessma.hpsocket.mbcs 和 org.jessma.hpsocket.unicode
- HPSocket for Java SDK 提供如下通訊組件:
1) TcpServer:TCP 通訊服務端組件,支持 PUSH/PULL 模型
2) TcpClient:TCP 通訊客戶端組件,支持 PUSH/PULL 模型
3) TcpAgent :TCP 通訊 Agent 組件,支持 PUSH/PULL 模型
4) UdpServer:UDP 通訊服務端組件,支持 PUSH 模型
5) UdpClient:UDP 通訊客戶端組件,支持 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:鏈接服務器 */
agent.connect("localhost", (short)5555, pdwConnID);
/* 5:處理通訊數據 */
// 響應 OnReceive / OnPullReceive 事件接收數據
// 使用 agent.send(dwConnID, data, data.length) 發送數據
/* 6:關閉通訊組件 */
agent.stop();
/* 7:銷燬通訊組件 */
TcpAgent.destroy(agent);
- 增長示例工程 TestEcho-4J,展現 HPSocket4J 的使用方法(包括 PULL 模型示例和性能測試示例)
> 優化數據收發策略:
-----------------
- Server 和 Agent 組件提供如下三種數據發送策略
1)PACK - 打包模式(默認):儘可能把多個發送操做的數據組合在一塊兒,增長傳輸效率
2)SAFE - 安全模式 :儘可能把多個發送操做的數據組合在一塊兒,控制傳輸速度,避免緩衝區溢出
3)DIRECT - 直接模式 :對每個發送操做都直接投遞,適用於負載不高但要求實時性較高的場合
- Server 和 Agent 組件提供如下兩種數據接收策略
1)SERIAL - 串行模式(默認):順序觸發同一鏈接的 OnReceive 和 OnClose/OnError 事件
2)PARALLEL - 並行模式:在不一樣的通訊線程中同時觸發同一鏈接的 OnReceive 和 OnClose/OnError 事件
> 其它更新:
-----------------
- IServer 的 GetClientAddress() 方法更名爲 GetRemoteAddress()
- IClient 的 Send() 方法刪除 「CONNID dwConnID」 參數
- IClient/IServer/IAgent 的 Send() 方法增長髮送數據緩衝區指針偏移量參數 「int iOffset」
- 增長 EnSendPolicy 枚舉類型,IServer/IAgent 增長髮送模式設置方法 SetSendPolicy()
- 增長 EnRecvPolicy 枚舉類型,IServer/IAgent 增長接收模式設置方法 SetRecvPolicy()
- IServer/IAgent 增長方法:BOOL GetAllConnectionIDs(),獲取全部鏈接的 CONNID
- IUdpServer 增長方法:SetPostReceiveCount(),設置 Receive 預投遞數量
- EnServerError / EnClientError 枚舉類型合併爲 EnSocketError
- EnSocketError / EnHandleResult / EnFetchResult 枚舉類型從原所在類中移到外部
- IClient/IServer/IAgent 增長方法:BOOL GetPendingDataLength(),獲取鏈接中未發出數據的長度
- HPSocket4C.dll 增長方法 SendPart(),支持指定緩衝區指針偏移量
- 增長 HPSocket for C# SDK(由 int 2e 提供)
- 增長 HPSocket 易語言支持庫(由 Yecate 提供)
- 公共代碼包 vc-common-src 更新爲 v2.3.5(參考:vc-common-src v2.3.5 的 Change Log)
> 升級說明:
-----------------
- HP-Socket v3.2.1 在功能上兼容 HP-Socket v3.1.3 及之前版本
- 接口有變化,須要根據提示修改程序代碼;注意:現有程序不能直接替換 v3.1.3 的 DLL
- EnServerError / EnClientError 枚舉類型合併爲 EnSocketError,注意一些枚舉值發生了變化
*** 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 及以前全部版本
*** 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 對象緩存列表設置了鎖定時間,提升訪問的安全性