HP-Socket
高性能网络通信框架
Version - 5.8.6
Bruce Liang
2022-01-18
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
1
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件、
客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP
信系统,提供 C/C++C#DelphiE(易语言JavaPython 等编程语言接口。
HP-Socket 对通信层完全封装,应用程序不必关注通信层的任何细节;HP-Socket
提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中。
为了让使用者能方便快速地学习和使用 HP-Socket,迅速掌握框架的设计思
想和使用方法,特此精心制作了大量 Demo 示例(如:PUSH 模型示例、PULL
模型示例、PACK 模型示例、性能测试示例以及其它编程语言示例)HP-Socket
目前支持 Windows Linux 平台。
通用性
HP-Socket 的唯一职责就是接收和发送字节流,参与应用程序的协议解析等工作。
HP-Socket 与应用程序通过接口进行交互,并完全解耦。任何应用只要实现 HP-
Socket 的接口规范都可以无缝整合 HP-Socket
易用性
易用性对所有通框架都是至关重要的,如果太难用还不如自己从头写一个来得方
便。因此,HP-Socket 的接口设计非常简单和统一。
HP-Socket 完全封装了所有底层通信细节,应用程序不必也不能干预底层通信操作。
通信连接被抽象 Connection IDConnection ID 为连接的唯一标识提供给应用
程序来处理不同的连接。
HP-Socket 提供 PUSH / PULL / PACK 等接收模型,应用程序可以灵活选择以手工
方式、半自动方式或全自动方式处理封解包,PULL / PACK 接收模型在降低封解包
处理复杂度的同时能大大减少出错几率。
高性能
Server 组件:基于 IOCP / EPOLL 通信模型,并结合缓存池、私有堆等技术实现高
效内存管理,支持超大规模、高并发通信场景。
Agent 组件:Agent 组件实质上是 Multi-Client 组件,与 Server 组件采用相同的
术架构。一个 Agent 组件对象可同时建立高效处理大规模 Socket 连接。
Client 组件:基于 Event Select / POLL 通信模型,每个组件对象创建一个通信线程
并管理一个 Socket 连接,适用于小规模客户端场景
伸缩
应用程序可以根据不同的容量要求通信规模和资源状况等现实场景调 HP-Socket
各项性能参数(如:工作线程的数量、缓存池的大小、发送模式和接收模式等),优化资源
配置,在满足应用需求的同时不必过度浪费资源。
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
2
................................................................................................................................................. 1
................................................................................................................................................. 2
1 ......................................................................................................................................... 4
1.1 整体架构 ................................................................................................................... 4
1.2 组件分类 ................................................................................................................... 6
1.3 组件接口 ................................................................................................................... 7
1.4 监听器接口 ............................................................................................................. 10
2 框架详述 ................................................................................................................................. 14
2.1 关键概念 ................................................................................................................. 14
2.1.1 接收模型 ......................................................................................................... 14
2.1.2 发送策略 ......................................................................................................... 17
2.1.3 OnSend 同步策略 ........................................................................................... 17
2.1.4 地址重用策略 ................................................................................................. 18
2.1.5 连接方式 ......................................................................................................... 19
2.1.6 连接绑定 ......................................................................................................... 20
2.1.7 等待停止 ......................................................................................................... 22
2.2 Server 组件 ............................................................................................................. 23
2.2.1 接口描述 ......................................................................................................... 23
2.2.2 工作流程 ......................................................................................................... 27
2.3 Agent 组件 .............................................................................................................. 29
2.3.1 接口描述 ......................................................................................................... 29
2.3.2 工作流程 ......................................................................................................... 32
2.4 Client 组件 .............................................................................................................. 33
2.4.1 接口描述 ......................................................................................................... 33
2.4.2 工作流程 ......................................................................................................... 36
2.5 UDP Node 组件 ...................................................................................................... 37
2.5.1 接口描述 ......................................................................................................... 37
2.5.2 工作流程 ......................................................................................................... 39
3 SSL .......................................................................................................................................... 41
3.1 组件接口 ................................................................................................................. 41
3.2 SSL 运行环境 ......................................................................................................... 43
3.3 SSL 握手 ................................................................................................................. 45
4 HTTP ....................................................................................................................................... 46
4.1 组件接口 ................................................................................................................. 46
4.2 监听器事件 ............................................................................................................. 49
4.3 Cookie 管理 ............................................................................................................ 53
4.4 启动 HTTP 通讯 ..................................................................................................... 57
5 UDP ARQ................................................................................................................................ 58
5.1 组件接口 ................................................................................................................. 58
5.2 握手协议 ................................................................................................................. 59
5.3 配置参数 ................................................................................................................. 60
6 线程池 ..................................................................................................................................... 62
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
3
6.1 组件接口 ................................................................................................................. 62
6.2 监听器事件 ............................................................................................................. 63
7 压缩 / 解压缩 ........................................................................................................................ 65
7.1 组件接口 ................................................................................................................. 65
7.1.1 压缩器组件接口 ............................................................................................. 65
7.1.2 解压器组件接口 ............................................................................................. 66
7.1.3 输出数据回调 ................................................................................................. 67
7.2 对象创建 ................................................................................................................. 67
8 Linux ....................................................................................................................................... 69
8.1 编译 ......................................................................................................................... 69
8.2 安装 ......................................................................................................................... 70
8.3 Android NDK .......................................................................................................... 70
8.3.1 ABIs ................................................................................................................ 70
8.3.2 功能特性开关 ................................................................................................. 71
8.3.3 其他选项 ......................................................................................................... 71
9 使用方式 ................................................................................................................................. 72
9.1 源代码 ..................................................................................................................... 72
9.2 静态库 ..................................................................................................................... 72
9.3 HPSocket DLL ........................................................................................................ 72
9.4 HPSocket4C DLL ................................................................................................... 73
9.5 扩展支持 ................................................................................................................. 74
10 ............................................................................................................................... 75
10.1 示例 Demo .............................................................................................................. 75
10.1.1 Windows 示例 ................................................................................................. 75
10.1.2 Linux 示例 ...................................................................................................... 76
10.2 辅助函数 ................................................................................................................. 78
10.3 FAQ ......................................................................................................................... 80
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
4
1
1.1 整体架构
HP-Socket 完全封装了底层通信细节,并为应用程序提供一套简单易用的并且与底层通
信完全无关的 API 接口,使应用程序获得高性能高伸缩性通信的同时,免除处理通信细节
的负担。HP-Socket API 接口模型如图 1.1-1 所示:
1.1-1 HP-Socket API 接口模型
HP-Socket 定义了组件接口(如:ITcpServer / IUdpClient)、 组件实现(如:CTcpServer
/ CUdpClient)和监听器接口(如ITcpServerListener / IUdpClientListener,其中:
组件接口:声明组件操作方法,应用程序创建组件对象后通过该接口来使用组件
组件实现类:实现组件接口,执行实际通信处工作,并向监听器报告通信事件
监听器接口:声明组件的通信事件回调方法
每个组件对象都会关联一个监听器对象(监听器对象的实现类由应用程序定义),当组
件对象触发一个通信事件时会调用监听器对象相应的回调方法应用程序在回调方法中处理
应用业务逻辑。 1.1-2 TCP Agent 为例展示了组件与应用程序的交互:
应用程序首先创建监听器对象和 TCP Agent 对象创建 TCP Agent 对象时传入监听器
象,把 TCP Agent 对象与监听器对象关联起来TCP Agent 对象创建完毕后,应用程序调用
TCP Agent 接口方法操作 TCP Agent 对象(如:Start / Connect / Send / Stop 等) TCP Agent
对象触发通信事件时,会调用监听器对象的回调方法(如:OnConnect / OnSend / OnReceive
/ Onclose 等)通知应用程序。
注意:监听器对象的异步回调方法是在组件的通信线程中执行的,因此回调方法不应执
行耗时较长的业务逻辑代码,同时要注意多线程同步问题,也应尽量避免使用锁。
HP-Socekt
通过设置连接绑定”能 协助应用程序巧妙地避免由于多线程同步和互斥锁
等导致的复杂性和性能问题。
HP-Socket
Component Interface
Listener Interface
Component Implement Class
1
My Application
Listener Implement Class
Logic Controller
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
5
1.1-2 TCP Agent 与应用程序交互示例
My Logic Controller My TCP Agent Listener TCP Agent
ITcpAgentListener := new()
<<create>>
Create Agent & Listener
Start Agent
Connect Operation
Send Operation
OnPrepareConnect Callback
OnConnect Callback
OnSend Callback
OnReceive Callback
OnClose Callback
Stop Operation
OnShutdown Callback
listener
ITcpAgent := new(listener)
<<create>>
agent
Start()
Connect(address, port)
OnPrepareConnect(connid)
OnConnect(connid)
OnHandshake(connid)
OnHandshake Callback
Send(connid, data, length)
OnSend(connid, data, length)
OnReceive(connid, data, length)
OnClose(connid, operation, code)
Stop()
OnShutdown()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
6
1.2 组件分类
HP-Socket 包含 31 个组件(其 9 SSL 组件将 3 详细讲解,8 HTTP 组件
将在 4 详细讲解)可根据通信角Client / Server通信协议TCP / UDP/HTTP)和
接收模型PUSH / PULL / PACK进行归类 1.2-1 列出了 TCP / UDP 组件的名称、接口、
监听器接口、实现类及其分类:
Name
Component Intface
Listener Intface
Role
Protocol
Recv
Model
TCP Server
ITcpServer
ITcpServerListener
Server
TCP
PUSH
TCP Pull Server
ITcpPullServer
ITcpServerListener
CTcpPullServer
Server
TCP
PULL
TCP Pack Server
ITcpPackServer
ITcpServerListener
Server
TCP
PACK
UDP Server
IUdpServer
IUdpServerListener
CUdpServer
Server
UDP
PUSH
UDP ARQ Server
IUdpArqServer
IUdpServerListener
Server
UDP
PUSH
TCP Agent
ITcpAgent
ITcpServerListener
CTcpAgent
Client
TCP
PUSH
TCP Pull Agent
ITcpPullAgent
ITcpAgentListener
Client
TCP
PULL
TCP Pack Agent
ITcpPackAgent
ITcpServerListener
CTcpPackAgent
Client
TCP
PACK
TCP Client
ITcpClient
ITcpClientListener
Client
TCP
PUSH
TCP Pull Client
ITcpPullClient
ITcpClientListener
CTcpPullClient
Client
TCP
PULL
TCP Pack Client
ITcpPackClient
ITcpClientListener
Client
TCP
PACK
UDP Client
IUdpClient
IUdpClientListener
CUdpClient
Client
UDP
PUSH
UDP ARQ Client
IUdpArqClient
IUdpClientListener
Client
UDP
PUSH
UDP Cast
IUdpCast
IUdpCastListener
CUdpCast
Client
UDP
PUSH
UDP Node
IUdpNode
IUdpNodeListener
Client
Server
UDP
PUSH
Thread Pool
IHPThreadPool
CHPThreadPool
--
--
--
1.2-1 组件分类
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
7
Agent 组件本质上是 Client 组件,一个 Agent 对象能同时管理多个客户端连接
根据实际使用场景,HP-Socket 中只实现了基于 TCP HTTP Agent 组件
UDP Cast 组件为组播和广播 UDP 而设计,可认为是一种特殊的 Client 组件
UDP Node 件提供独立的无连 UDP 口,同时支持单播、组播和广播模式
基于 TCP 的组件都分别提供 PUSH PULL PACK 三种接收模
Thread Pool 组件是 HP-Socket 实现的高效易用的线程池组件
1.3 组件接口
ServerAgent Client 的组件接口定义如 1.3-1 1.3-3 所示,组件接口定义了组件
提供的所有操作方法。其中,PULL 模型接口多重继承 IPullSocket / IPullCliet 接口,它提
供了 Fetch(dwConnID, pData, iDataLength) 方法,让应用程序从组件中拉取数据。
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
8
1.3-1 Server 组件接口
IUdpServer
+SetMaxDatagramSize(dwMaxDatagramSize: DWORD): void
+GetMaxDatagramSize(): DWORD
+SetPostReceiveCount(dwPostReceiveCount: DWORD): void
+GetPostReceiveCount(): DWORD
+SetDetectAttempts(dwDetectAttempts: DWORD): void
+SetDetectInterval(dwDetectInterval: DWORD): void
+GetDetectAttempts(): DWORD
+GetDetectInterval(): DWORD
ITcpPullServer
+ToPull(pServer: IServer): IPullSocket
+ToServer(pPullSocket: IPullSocket): ITcpServer
ITcpServer
+SendSmallFile(dwConnID: CONNID, lpszFileName: LPCTSTR, pHead: LPWSABUF, pTail: LPWSABUF): BOOL
+SetAcceptSocketCount(dwAcceptSocketCount: DWORD): void
+SetSocketBufferSize(dwSocketBufferSize: DWORD): void
+SetSocketListenQueue(dwSocketListenQueue: DWORD): void
+SetKeepAliveTime(dwKeepAliveTime: DWORD): void
+SetKeepAliveInterval(dwKeepAliveInterval: DWORD): void
+GetAcceptSocketCount(): DWORD
+GetSocketBufferSize(): DWORD
+GetSocketListenQueue(): DWORD
+GetKeepAliveTime(): DWORD
+GetKeepAliveInterval(): DWORD
IServer
+Start(lpszBindAddress: LPCTSTR, usPort: USHORT): BOOL
+GetListenAddress(lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
IComplexSocket
+Stop(): BOOL
+Wait(dwMilliseconds: DWORD): BOOL
+Send(dwConnID: CONNID, pBuffer: BYTE, iLength: int, iOffset: int): BOOL
+SendPackets(dwConnID: CONNID, pBuffers: WSABUF, iCount: int): BOOL
+Disconnect(dwConnID: CONNID, bForce: BOOL): BOOL
+DisconnectLongConnections(dwPeriod: DWORD, bForce: BOOL): BOOL
+DisconnectSilenceConnections(dwPeriod: DWORD, bForce: BOOL): BOOL
+PauseReceive(dwPeriod: DWORD, bPause: BOOL): BOOL
+IsPauseReceive(dwPeriod: DWORD, bPaused: BOOL): BOOL
+IsSecure(): BOOL
+IsConnected(dwConnID: CONNID): BOOL
+SetConnectionExtra(dwConnID: CONNID, pExtra: PVOID): BOOL
+GetConnectionExtra(dwConnID: CONNID, ppExtra: PVOID): BOOL
+HasStarted(): BOOL
+GetState(): EnServiceState
+GetMaxConnectionCount(): DWORD
+SetMaxConnectionCount(dwMaxConnectionCount: DWORD): void
+GetConnectionCount(): DWORD
+GetAllConnectionIDs(pIDs: CONNID, dwCount: DWORD): BOOL
+GetConnectPeriod(dwConnID: CONNID, dwPeriod: DWORD): BOOL
+GetSilencePeriod(dwConnID: CONNID, dwPeriod: DWORD): BOOL
+GetLocalAddress(dwConnID: CONNID, lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetRemoteAddress(dwConnID: CONNID, lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetLastError(): EnSocketError
+GetLastErrorDesc(): LPCTSTR
+GetPendingDataLength(dwConnID: CONNID, iPending: int): BOOL
+SetReuseAddressPolicy(enReusePolicy: EnReuseAddressPolicy): void
+SetSendPolicy(enSendPolicy: EnSendPolicy): void
+SetMarkSilence(bMarkSilence: BOOL): void
+IsMarkSilence(): BOOL
+SetFreeSocketObjLockTime(dwFreeSocketObjLockTime: DWORD): void
+SetFreeSocketObjPool(dwFreeSocketObjPool: DWORD): void
+SetFreeBufferObjPool(dwFreeBufferObjPool: DWORD): void
+SetFreeSocketObjHold(dwFreeSocketObjHold: DWORD): void
+SetFreeBufferObjHold(dwFreeBufferObjHold: DWORD): void
+SetWorkerThreadCount(dwWorkerThreadCount: DWORD): void
+GetReuseAddressPolicy(): EnReuseAddressPolicy
+GetSendPolicy(): EnSendPolicy
+GetFreeSocketObjLockTime(): DWORD
+GetFreeSocketObjPool(): DWORD
+GetFreeBufferObjPool(): DWORD
+GetFreeSocketObjHold(): DWORD
+GetFreeBufferObjHold(): DWORD
+GetWorkerThreadCount(): DWORD
<<destroy>>-IComplexSocket()
IPullSocket
+Fetch(dwConnID: CONNID, pData: BYTE, iLength: int): EnFetchResult
+Peek(dwConnID: CONNID, pData: BYTE, iLength: int): EnFetchResult
<<destroy>>-IPullSocket()
IPackSocket
+SetMaxPackSize(dwMaxPackSize: DWORD): void
+SetPackHeaderFlag(usPackHeaderFlag: USHORT): void
+GetMaxPackSize(): DWORD
+GetPackHeaderFlag(): USHORT
<<destroy>>-IPackSocket()
ITcpPackServer
+ToPack(pServer: IServer): IPackSocket
+ToServer(pPackSocket: IPackSocket): ITcpServer
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
9
1.3-2 Agent 组件接口
IComplexSocket
+Stop(): BOOL
+Wait(dwMilliseconds: DWORD): BOOL
+Send(dwConnID: CONNID, pBuffer: BYTE, iLength: int, iOffset: int): BOOL
+SendPackets(dwConnID: CONNID, pBuffers: WSABUF, iCount: int): BOOL
+Disconnect(dwConnID: CONNID, bForce: BOOL): BOOL
+DisconnectLongConnections(dwPeriod: DWORD, bForce: BOOL): BOOL
+DisconnectSilenceConnections(dwPeriod: DWORD, bForce: BOOL): BOOL
+PauseReceive(dwPeriod: DWORD, bPause: BOOL): BOOL
+IsPauseReceive(dwPeriod: DWORD, bPaused: BOOL): BOOL
+IsSecure(): BOOL
+IsConnected(dwConnID: CONNID): BOOL
+SetConnectionExtra(dwConnID: CONNID, pExtra: PVOID): BOOL
+GetConnectionExtra(dwConnID: CONNID, ppExtra: PVOID): BOOL
+HasStarted(): BOOL
+GetState(): EnServiceState
+GetMaxConnectionCount(): DWORD
+SetMaxConnectionCount(dwMaxConnectionCount: DWORD): void
+GetConnectionCount(): DWORD
+GetAllConnectionIDs(pIDs: CONNID, dwCount: DWORD): BOOL
+GetConnectPeriod(dwConnID: CONNID, dwPeriod: DWORD): BOOL
+GetSilencePeriod(dwConnID: CONNID, dwPeriod: DWORD): BOOL
+GetLocalAddress(dwConnID: CONNID, lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetRemoteAddress(dwConnID: CONNID, lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetLastError(): EnSocketError
+GetLastErrorDesc(): LPCTSTR
+GetPendingDataLength(dwConnID: CONNID, iPending: int): BOOL
+SetReuseAddressPolicy(enReusePolicy: EnReuseAddressPolicy): void
+SetSendPolicy(enSendPolicy: EnSendPolicy): void
+SetMarkSilence(bMarkSilence: BOOL): void
+IsMarkSilence(): BOOL
+SetFreeSocketObjLockTime(dwFreeSocketObjLockTime: DWORD): void
+SetFreeSocketObjPool(dwFreeSocketObjPool: DWORD): void
+SetFreeBufferObjPool(dwFreeBufferObjPool: DWORD): void
+SetFreeSocketObjHold(dwFreeSocketObjHold: DWORD): void
+SetFreeBufferObjHold(dwFreeBufferObjHold: DWORD): void
+SetWorkerThreadCount(dwWorkerThreadCount: DWORD): void
+GetReuseAddressPolicy(): EnReuseAddressPolicy
+GetSendPolicy(): EnSendPolicy
+GetFreeSocketObjLockTime(): DWORD
+GetFreeSocketObjPool(): DWORD
+GetFreeBufferObjPool(): DWORD
+GetFreeSocketObjHold(): DWORD
+GetFreeBufferObjHold(): DWORD
+GetWorkerThreadCount(): DWORD
<<destroy>>-IComplexSocket()
IA gent
+Start(lpszBindAddress: LPCTSTR, pdwConnID: PCONNID, bAsyncConnect: BOOL, pExtra: PVOID, usLocalPort: USHORT): BOOL
+Connect(lpszRemoteAddress: LPCTSTR, usPort: USHORT, pdwConnID: CONNID, pExtra: PVOID, usLocalPort: USHORT, lpszLocalAddress: LPCTSTR): BOOL
+GetRemoteHost(dwConnID: CONNID, lpszHost: TCHAR, iHostLen: int, usPort: USHORT): BOOL
ITcpAgent
+SendSmallFile(dwConnID: CONNID, lpszFileName: LPCTSTR, pHead: LPWSABUF, pTail: LPWSABUF): BOOL
+SetSocketBufferSize(dwSocketBufferSize: DWORD): void
+SetKeepAliveTime(dwKeepAliveTime: DWORD): void
+SetKeepAliveInterval(dwKeepAliveInterval: DWORD): void
+GetSocketBufferSize(): DWORD
+GetKeepAliveTime(): DWORD
+GetKeepAliveInterval(): DWORD
IPullSocket
+Fetch(dwConnID: CONNID, pData: BYTE, iLength: int): EnFetchResult
+Peek(dwConnID: CONNID, pData: BYTE, iLength: int): EnFetchResult
<<destroy>>-IPullSocket()
ITcpPullAgent
+ToPull(pAgent: IAgent): IPullSocket
+ToAgent(pPullSocket: IPullSocket): ITcpAgent
IPackSocket
+SetMaxPackSize(dwMaxPackSize: DWORD): void
+SetPackHeaderFlag(usPackHeaderFlag: USHORT): void
+GetMaxPackSize(): DWORD
+GetPackHeaderFlag(): USHORT
<<destroy>>-IPackSocket()
ITcpPackAgent
+ToPack(pAgent: IAgent): IPackSocket
+ToAgent(pPackSocket: IPackSocket): ITcpAgent
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
10
1.3-3 Client 组件接口
1.4 监听器接口
ServerAgent Client 的监听器接口定义如图 1.4-1 1.4-3 所示
IClient
+Start(lpszRemoteAddress: LPCTSTR, usPort: USHORT, bAsyncConnect: BOOL, lpszBindAddress: LPCTSTR, usLocalPort: USHORT): BOOL
+Stop(): BOOL
+Wait(dwMilliseconds: DWORD): BOOL
+Send(pBuffer: BYTE, iLength: int, iOffset: int): BOOL
+SendPackets(pBuffers: WSABUF, iCount: int): BOOL
+PauseReceive(bPause: BOOL): BOOL
+IsPauseReceive(bPaused: BOOL): BOOL
+IsSecure(): BOOL
+IsConnected(): BOOL
+SetExtra(pExtra: PVOID): void
+GetExtra(): PVOID
+HasStarted(): BOOL
+GetState(): EnServiceState
+GetLastError(): EnSocketError
+GetLastErrorDesc(): LPCTSTR
+GetConnectionID(): CONNID
+GetLocalAddress(lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetRemoteHost(lpszHost: TCHAR, iHostLen: int, usPort: USHORT): BOOL
+GetFreeBufferPoolSize(): DWORD
+GetPendingDataLength(iPending: int): BOOL
+SetFreeBufferPoolSize(dwFreeBufferPoolSize: DWORD): void
+SetFreeBufferPoolHold(dwFreeBufferPoolHold: DWORD): void
+GetFreeBufferPoolHold(): DWORD
+SetReuseAddressPolicy(enReusePolicy: EnReuseAddressPolicy): void
+GetReuseAddressPolicy(): EnReuseAddressPolicy
<<destroy>>-IClient()
ITcpClient
+SendSmallFile(lpszFileName: LPCTSTR, pHead: LPWSABUF, pTail: LPWSABUF): BOOL
+SetSocketBufferSize(dwSocketBufferSize: DWORD): void
+SetKeepAliveTime(dwKeepAliveTime: DWORD): void
+SetKeepAliveInterval(dwKeepAliveInterval: DWORD): void
+GetSocketBufferSize(): DWORD
+GetKeepAliveTime(): DWORD
+GetKeepAliveInterval(): DWORD
IUdpClient
+SetMaxDatagramSize(dwMaxDatagramSize: DWORD): void
+GetMaxDatagramSize(): DWORD
+SetDetectAttempts(dwDetectAttempts: DWORD): void
+SetDetectInterval(dwDetectInterval: DWORD): void
+GetDetectAttempts(): DWORD
+GetDetectInterval(): DWORD
IUdpCast
+SetMaxDatagramSize(dwMaxDatagramSize: DWORD): void
+GetMaxDatagramSize(): DWORD
+SetCastMode(enCastMode: EnCastMode): void
+GetCastMode(): EnCastMode
+SetMultiCastTtl(iMCTtl: int): void
+GetMultiCastTtl(): int
+SetMultiCastLoop(bMCLoop: BOOL): void
+IsMultiCastLoop(): BOOL
+GetRemoteAddress(lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
IPullClient
+Fetch(pData: BYTE, iLength: int): EnFetchResult
+Peek(pData: BYTE, iLength: int): EnFetchResult
<<destroy>>-IPullClient()
ITcpPullClient
+ToPull(pClient: IClient): IPullClient
+ToClient(pPullClient: IPullClient): ITcpClient
IPackClient
+SetMaxPackSize(dwMaxPackSize: DWORD): void
+SetPackHeaderFlag(usPackHeaderFlag: USHORT): void
+GetMaxPackSize(): DWORD
+GetPackHeaderFlag(): USHORT
<<destroy>>-IPackClient()
ITcpPackClient
+ToPack(pClient: IClient): IPackClient
+ToClient(pPackClient: IPackClient): ITcpClient
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
11
1.4-1 Server 监听器接口
1.4-2 Agent 监听器接口
IComplexSocketListenerT<T>
+OnShutdown(pSender: T): EnHandleResult
IServerListenerT<T>
+OnPrepareListen(pSender: T, soListen: SOCKET): EnHandleResult
+OnAccept(pSender: T, dwConnID: CONNID, soClient: SOCKET): EnHandleResult
IUdpServerListenerITcpServerListener
ISocketListenerT<T>
+OnHandShake(pSender: ITcpClient, dwConnID: CONNID): EnHandleResult
+OnSend(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, iLength: int): EnHandleResult
+OnClose(pSender: T, dwConnID: CONNID, enOperation: EnSocketOperation, iErrorCode: int): EnHandleResult
<<destroy>>-ISocketListenerT()
IComplexSocketListenerT<T>
+OnShutdown(pSender: T): EnHandleResult
IAgentListenerT<T>
+OnPrepareConnect(pSender: T, dwConnID: CONNID, socket: SOCKET): EnHandleResult
+OnConnect(pSender: T, dwConnID: CONNID): EnHandleResult
ITcpAgentListener
ISocketListenerT<T>
+OnHandShake(pSender: ITcpClient, dwConnID: CONNID): EnHandleResult
+OnSend(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, iLength: int): EnHandleResult
+OnClose(pSender: T, dwConnID: CONNID, enOperation: EnSocketOperation, iErrorCode: int): EnHandleResult
<<destroy>>-ISocketListenerT()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
12
1.4-3 Client 监听器接口
HP-Socket 没有为 PUSH / PULL / PACK 模型组件定义单独的监听器接口,它们使用
同的监听器接口,区别在于:PUSH PACK 模型组件接收到数据时会触发监听器对象的
OnReceive(pSender, dwConnID, pData, iLength) 事件,而 PULL 模型组件接收到数据时会
发监听器对象 OnReceive(pSender, dwConnID, iLength) 事件。事件的含义如表 1.4-1 所示:
ISocketListenerT
OnHandShake(pSender, dwConnID)
握手完成
OnSend(pSender, dwConnID, pData, iLength)
数据已发送
OnReceive(pSender, dwConnID, pData, iLength)
数据到达
PUSH
OnReceive(pSender, dwConnID, iLength)
数据到达
PULL
OnClose(pSender, dwConnID, enOperation, iErrorCode)
连接关闭
IComplexSocketListenerT
OnShutdown(pSender)
关闭组件
IServerListenerT
OnPrepareListen(pSender, soListen)
准备监听
OnAccept(pSender, dwConnID, soClient)
接受连接
IAgentListenerT
OnPrepareConnect(pSender, dwConnID, socket)
准备连接
OnConnect(pSender, dwConnID)
完成连接
IClientListenerT
OnPrepareConnect(pSender, dwConnID, socket)
准备连接
OnConnect(pSender, dwConnID)
完成连接
1.4-1 监听器接口事件
IClientListenerT<T>
+OnPrepareConnect(pSender: T, dwConnID: CONNID, socket: SOCKET): EnHandleResult
+OnConnect(pSender: T, dwConnID: CONNID): EnHandleResult
ITcpClientListener IUdpCastListenerIUdpClientListener
ISocketListenerT<T>
+OnHandShake(pSender: ITcpClient, dwConnID: CONNID): EnHandleResult
+OnSend(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, iLength: int): EnHandleResult
+OnClose(pSender: T, dwConnID: CONNID, enOperation: EnSocketOperation, iErrorCode: int): EnHandleResult
<<destroy>>-ISocketListenerT()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
13
监听器事件回调方法返回值的类型为 EnHandleResult
HR_OK 成功处理
HR_IGNORE 忽略处理
HR_ERROR 处理失败
注意:
OnReceive / OnPrepareListen / OnAccept / OnPrepareConnect / OnConnect /
OnHandShake
事件回调方法返回
HR_ERROR
时,组件会立即中断连接。
为了使非
SSL
组件和
SSL
组件的处理流程一致,
HP-Socket v4.0.x
开始,非
SSL
组件
也会触发
OnHandShake
事件。因此,当组件接收到
OnHandShake
事件即说明连接已建立,
并可以开始通信。
EnHandleResult
<<enumeration>>
+HR_OK
+HR_IGNORE
+HR_ERROR
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
14
2 框架详述
2.1 关键概念
2.1.1 接收模型
如表 1.2-1 所示,HP-Socket TCP 组件支持 PUSHPULL PACK 三种接收模型:
PUSH 模型:组件接收到数据时会触发监听器对象的 OnReceive(pSender, dwConnID,
pData, iLength) 事件,把数据“推”给应用程序。
PULL 模型:组件接收到数据时会触发监听器对象的 OnReceive(pSender, dwConnID,
iTotalLength) 事件告诉应用程序当前已经接收到多少数据应用程序检查数据的
长度,如果满足需要则调用组件的 Fetch(dwConnID, pData, iDataLength) 方法把需
要的数据“拉”出来。
PACK 模型:PACK 模型系列组件是 PUSH PULL 模型的结合体,应用程序不
必处理分包(如:PUSH与数据抓取(如:PULL组件保证每 OnReceive
件都向应用程序提供一个完整数据包
三种模型的比较如图 2.1.1-1 所示:
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
15
通信组件
TcpServer/TcpClient/TcpAgent
UdpServer/UdpClient/UdpCast
应用程序
HP-Socket
OnReceive(pSender, dwConnID, pData, iLength)
PUSH 模型
通信组件
TcpPullServer/TcpPullClient/TcpPullAgent
应用程序
HP-Socket
OnReceive(pSender, dwConnID, iTotalLength)
PULL 模型
Fetch(dwConnID, pData, iDataLength)
通信组件
TcpPackServer/TcpPackClient/TcpPackAgent
应用程序
HP-Socket
OnReceive(pSender, dwConnID, pData, iLength)
PACK 模型
每个 OnReceive()事件都返回一个完整数据包
2.1.1-1 接收模型
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
16
PUSH 模型组件触发监听器对象的 OnReceive(pSender, dwConnID, pData, iLength)
事件时,应用程序需要立即处理接收到的数据,如:粘包处理协议解析等组件
不会对应用层的数据处理工作提供任何协助。
PULL 模型组件触发监听器对象 OnReceive(pSender, dwConnID, iTotalLength)
件时,应用程序根据应用层协议检测接收到的数据长度iTotalLength否满足处
理条件,选择性地进行处理。当 iTotalLength 小于当前期望的长度时可以忽略本次
iTotalLength
Fetch(dwConnID, pData, iDataLength) 方法把需要的数据拉取出来,直到剩余的数
据长度小于当前期望的长度。
Fetch(dwConnID, pData, iDataLength) 方法返回值的类型 EnFetchResult
FR_OK 成功拉取
HR_LENGTH_TOO_LONG 拉取的长度超过实际数据长度
HR_DATA_NOT_FOUND 没有数据可拉取,可能连接已被关闭
注意:只有当 Fetch(dwConnID, pData, iDataLength)方法返回 FR_OK 时,数据才会被
拉取出来。另外,PULL 模型组件还提供 Peek(dwConnID, pData, iDataLength)方法用于窥
探接收缓冲区,该方法不会移除缓冲区数据。
PULL 模型适用于完全清楚应用层协议,并且应用层协议可以根据当前数据包得知下一
个数据包长度的场景。典型的场景 Head + BodyHead 长度固定,第一个数据包 Head
通过 Head 得知 Body 的长度,接收完 Body 之后下一个数据包一定为 Head
注意:通过
PULL
模型与应用层协议的相互配合,使得应用程序可以免除粘包处理和
分拆包工作,从而减少应用程序的负担。
PACK 模型组件触发监听器对象的 OnReceive(pSender, dwConnID, pData, iLength)
事件时,会保证 pData 是一个完整的数据包。PACK 模型组件会对应用程序发送的
每个数据包自动加上 4 字节(32 位)的包头,组件接收到数据时根据包头信息自
动分包,每个完整数据包通过 OnReceive 事件发送给应用程序
PACK 包头格式:
XXXXXXXXXX YYYYYYYYYYYYYYYYYYYYYY
EnFetchResult
<<enumeration>>
+FR_OK
+FR_LENGTH_TOO_LONG
+FR_DATA_NOT_FOUND
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
17
10 X 为包头标识位,用于数据包校验有效包头标识取值范 0 ~ 10230x3FF
当包头标识等于 0 时不校验包头。后 22 Y 为长度位,记录包体长度。有效数据包最
长度不能超过 41943030x3FFFFF)字节,默认长度限制为:2621440x40000)字节。
用程序可以通过 SetPackHeaderFlag() SetMaxPackSize() 分别设置包头标识与最大包长
制。
2.1.2 发送策略
对于 IClient 系列组件,当应用程序调用组件的 Send()
SendPackets()
SendSmallFile()
方法发送数据时,组件内部会把数据缓存起来,在适当的时机再发送出去。
对于 IServer IAgent Send()
SendPackets()
SendSmallFile() 方法发送数据时,根据不同的发送策略会有不同的处理方式。
(发送策略通
SetSendPolicy(enSendPolicy)
方法进行设置
SP_PACK :打包策略(默认)
尽量把多个发送操作的数据组合在一起发送,增加传输效率。
SP_SAFE :安全策略
尽量把多个发送操作的数据组合在一起发送,并尽量避免缓冲区溢出。
SP_DIRECT 直接策略
对每一个发送操作都直接投递,适用于负载不高但要求实时性较高的场合。
注:
SP_DIRECT
通常与
TCP_NODELAY Socket
选项配合使用来获得最低延
时。(通过
SetSendPolicy(SP_DIRECT)
配合
SetNoDelay(TRUE)
实现)
对于 SP_PACK SP_SAFE 策略,组件内部会缓存待发送的数据。另外,应用程序
以调用组件的 GetPendingDataLength(dwConnID, iPending) 方法获取指定连接的未发出数据
量,实现流量控制。
注意:基于
Linux
Socket
模型特点,
Linux
平台的通信组件不支持发送策略设置,
Linux
通信组件的发送策略均为
SP_PACK
也就是说,
SetSendPolicy(enSendPolicy)
方法
Linux
通信组件无作用。
2.1.3 OnSend 同步策
HP-Socket v5.4.2 版本开始,IServer IAgent 系列组件支持对 OnSend 事件设置同步
略。
EnSendPolicy
<<enumeration>>
+SP_PACK
+SP_SAFE
+SP_DIRECT
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
18
OnSend
事件同步策略通过
SetOnSendSyncPolicy(enSyncPolicy)
方法进行设置
OSSP_NONE :不同步(默认)
不同步 OnSend 事件,可能同时触发 OnReceive OnClose 事件。
OSSP_CLOSE :同步 OnClose
只同步 OnClose 事件,可能同时触发 OnReceive 事件。
OSSP_RECEIVE :同步 OnReceive
(只用于 TCP 组件)同步 OnReceive OnClose 事件,不可能同时触发
OnReceive OnClose 事件。
OnSend 事件对于一般应用程序来说意义不大因此采用默认同步策略 OSSP_NONE
可,这种情况下 OnSend 事件不是线程安全的,在处理 OnSend 事件的过程中可能会同时触
OnReceive OnClose 事件OSSP_CLOSE 同步策略则会确保在处理 OnSend 事件的过程
中不可能触发 OnClose 事件OSSP_RECEIVE 同步策略则会确保在处 OnSend 事件的
程中不可能触 OnReceive OnClose 事件
注意:基于
Linux
Socket
模型特点,
Linux
平台的通信组件不支持
OnSend
事件同步
策略设置,所有
Linux
版本的
IServer
IAgent
通信组件的
OnSend
事件同步策略均为
OSSP_CLOSE
也就是说,
SetOnSendSyncPolicy(enSyncPolicy)
方法对
Linux
通信组件无效。
2.1.4 地址重用策略
HP-Socket v5.7.x 版本开始,所有通信组件都支持设置地址重用策略
(地址重用策略通过
SetReuseAddressPolicy(enReusePolicy)
方法进行设置
RAP_NONE :不重用
Windows
SO_EXCLUSIVEADDRUSE = TRUE
SO_REUSEADDR = FALSE
Linux/Unix
SO_REUSEADDR = FALSE
EnOnSendSyncPolicy
<<enumeration>>
+OSSP_NONE
+OSSP_CLOSE
+OSSP_RECEIVE
EnReuseAddressPolicy
<<enumeration>>
+RAP_NONE
+RAP_ADDR_ONLY
+RAP_ADDR_AND_PORT
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
19
SO_REUSEPORT = FALSE
RAP_ADDR_ONLY :仅重用地址(默认)
Windows
SO_EXCLUSIVEADDRUSE = FALSE
SO_REUSEADDR = FALSE
Linux/Unix
SO_REUSEADDR = TRUE
SO_REUSEPORT = FALSE
RAP_ADDR_AND_PORT :重用地址和端口
Windows
SO_EXCLUSIVEADDRUSE = FALSE
SO_REUSEADDR = TRUE
Linux/Unix
SO_REUSEADDR = TRUE
SO_REUSEPORT = TRUE
不同操作系统平台对地址重用的设置方式和表现行为存在差异在设置之前必须充分理
解这些选项在不同操作系统平台中行为。如:Windows 通过 SO_EXCLUSIVEADDRUSE
SO_REUSEADDR Socket 项设置地址重用,并且 SO_REUSEADDR 的语义类似于 Linux/Unix
SO_REUSEPORT Socket 选项;Linux/Unix 通过 SO_REUSEADDR SO_REUSEPORT
Socket 选项设置地址重用,BSD 系统支持 SO_REUSEPORT 项,Solaris 系统不支持Linux
系统在内核版 3.9.0 后才支持。
2.1.5 连接方式
HP-Socket 所有组件的通信过程都是异步的,如:调用组件 Send() 方法会立即返回,
稍后监听器会接收到 OnSend() 事件获知发送了多少数据,或者会接收 OnClose() 事件可
获知发送失败原因。
HP-Socket IClient IAgent 组件向服务器发起连接的过程可以是同步或异步的。
同步是指组件的连接方法IClient - Start()IAgent - Connect())等到建立连接成功或失败
再返回(返回 TRUE FALSE
异步连接是指组件的连接方法 Start() / Connect() 立即返回,如果 Start() / Connect()
返回成功(TRUE)则稍后会接收 OnConnect() OnClose() 事件,收到前者则说明连接
成功,收到后者则说明连接失败。注意:如果 Start() / Connect() 返回失败FALSE则稍后
不一定能接收 OnClose() 事件。因此,对于异步连接也必须检 Start() / Connect() 的返回
值,当返回失败FALSE)则立即可以断定连接失败。
IClient 建立连接方法:
BOOL Start(lpszRemoteAddress, usPort, bAsyncConnect = TRUE,
lpszBindAddress = nullptr, usLocalPort = 0)
参数 bAsyncConnect 指示是否采用异步连接方式(默认:TRUE,如果 Start()方法返回
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
20
失败可以调用组件的 GetLastError() GetLastErrorDesc() 方法获取错误代码和错误描述
如果 Start() GetConnectionID()
Connection ID
注意:
IUdpCast
组件的
Star()
方法忽略
bAsyncConnect
参数。
IAgent 建立连接方法:
BOOL Start(lpszBindAddress = nullptr, bAsyncConnect = TRUE)
BOOL Connect(lpszRemoteAddress, usPort, pdwConnID = nullptr,
pExtra = nullptr, usLocalPort = 0)
Start() 方法启 IAgent 组件并指定连接方式,参数 bAsyncConnect 指示是否采用异步
认:TRUE,如果 Start() GetLastError()
GetLastErrorDesc() 方法获取错误代码和错误描述。注意:Start() 方法在整个通信周期中只
需调用 1 次。
Connect() 方法与指定服务器建立连接参数 pdwConnID 用来获取本连接 Connection
ID(默认:nullptr不获取)参数 pExtra 连接绑定数据(默认nullptr不设置)
如果 Connect() 方法返回失败可以调 Windows API 函数 ::GetLastError() 获取 Windows
错误代码;如果设置了 pExtra,这时也要手工释放
无论是同步或异步连接,成功完成连接的过程中都会先后触发监听器的两个事件:
OnPrepareConnect(pSender, dwConnID, socket)
OnConnect pSender, dwConnID)
其中 OnPrepareConnect(pSender, dwConnID, socket) 在发起连接前触发,socket 是本地
SOCKET 柄,可以在该事件中通 setsockopt() / WSAIoctl() 等方法设 SOCKET 选项。
OnConnect(pSender, dwConnID) 则在连接建立成功后触发。
2.1.6 连接绑定
对于 IClient 系列组件,一个组件对象对应一个 Connection ID 和一个通信连接,因此很
容易把通信连接与应用层数据关联起来。应用程序与组件交互时直接通知组件处理数据即
可(如:Send( pData, iLength)。如图 2.1.5-1 所示:
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
21
2.1.5-1 IClient 组件连接示意图
注意:对于
IClient
组件,可以通过
SetExtra() / GetExtra()
方法绑定、获取附加数据。
对于 IServer IAgent 系列组件,一个组件对象管理多个通信连接HP-Socket 把通信
连接抽象为 Connection ID,应用程序与组件交互时,需要指 Connection ID 来告知组件
理哪个连接(如Send(dwConnID, pData, iLength) 。如图 2.1.5-2 示:
2.1.5-2 IServer/IAgent 组件连接示意图
应用程序为建立 Connection ID 与应用层数据的对应关系通常需要维护一张映射
(如:map<CONNID, TMyAppData*>从而不但增加了应用程序的负担;另外,由于运行
在多线程环境下对映射表的读写操作需要进行同步处理,从而降低了应用程序的并发性能。
HP-Socket IServer IAgent 系列组件提供以下方法组绑定 Connection ID 和应用层数
据,尽量避免让应用程序维护映射表
BOOL SetConnectionExtra(CONNID dwConnID, PVOID pExtra)
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
22
BOOL GetConnectionExtra(CONNID dwConnID, PVOID* ppExtra)
通常的应用情景如下:
1) OnAccept() / OnConnect() 事件中调 SetConnectionExtra(dwConnID, pExtra)
Connection ID 和应用层数据进行绑定。
2) OnReceive() / OnSend() 事件中调用 GetConnectionExtra(dwConnID, ppExtra)
取出与 Connection ID 绑定的应用层数据,执行相应业务逻辑处理
3) OnClose() 事件中取消 Connection ID 和应用层数据的绑定清除应用层数据
并释放资源。
注意:由于
HP-Socket
已经确保了
OnReceive() / OnClose()
等事件的线程安全,因此应
用程序可以放心使用连接绑定机制,不用担心同步问题。
2.1.7 等待停止
HP-Socket v5.7.x 版本开始,为所有组件(包括 IHPThreadPool)增加等待停止方法:
Wait()该方法的行为很简单:如果组件的状态为“正在运行则执行等待否则立刻返回
Wait()主要用于命令行进程或后台进程,实现“组件停止后自动退出程序”等功能。
等待停止方法:
BOOL Wait(dwMilliseconds =INFINITE)
参数 dwMilliseconds 设置等待超时时间(毫秒,默认:INFINITE,永不超时),超时返
FALSE,正常退出返 TRUE
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
23
2.2 Server 组件
2.2.1 接口描述
2.2.1-1 Server 组件接口
IUdpServer
+SetMaxDatagramSize(dwMaxDatagramSize: DWORD): void
+GetMaxDatagramSize(): DWORD
+SetPostReceiveCount(dwPostReceiveCount: DWORD): void
+GetPostReceiveCount(): DWORD
+SetDetectAttempts(dwDetectAttempts: DWORD): void
+SetDetectInterval(dwDetectInterval: DWORD): void
+GetDetectAttempts(): DWORD
+GetDetectInterval(): DWORD
ITcpPullServer
+ToPull(pServer: IServer): IPullSocket
+ToServer(pPullSocket: IPullSocket): ITcpServer
ITcpServer
+SendSmallFile(dwConnID: CONNID, lpszFileName: LPCTSTR, pHead: LPWSABUF, pTail: LPWSABUF): BOOL
+SetAcceptSocketCount(dwAcceptSocketCount: DWORD): void
+SetSocketBufferSize(dwSocketBufferSize: DWORD): void
+SetSocketListenQueue(dwSocketListenQueue: DWORD): void
+SetKeepAliveTime(dwKeepAliveTime: DWORD): void
+SetKeepAliveInterval(dwKeepAliveInterval: DWORD): void
+GetAcceptSocketCount(): DWORD
+GetSocketBufferSize(): DWORD
+GetSocketListenQueue(): DWORD
+GetKeepAliveTime(): DWORD
+GetKeepAliveInterval(): DWORD
IServer
+Start(lpszBindAddress: LPCTSTR, usPort: USHORT): BOOL
+GetListenAddress(lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
IComplexSocket
+Stop(): BOOL
+Wait(dwMilliseconds: DWORD): BOOL
+Send(dwConnID: CONNID, pBuffer: BYTE, iLength: int, iOffset: int): BOOL
+SendPackets(dwConnID: CONNID, pBuffers: WSABUF, iCount: int): BOOL
+Disconnect(dwConnID: CONNID, bForce: BOOL): BOOL
+DisconnectLongConnections(dwPeriod: DWORD, bForce: BOOL): BOOL
+DisconnectSilenceConnections(dwPeriod: DWORD, bForce: BOOL): BOOL
+PauseReceive(dwPeriod: DWORD, bPause: BOOL): BOOL
+IsPauseReceive(dwPeriod: DWORD, bPaused: BOOL): BOOL
+IsSecure(): BOOL
+IsConnected(dwConnID: CONNID): BOOL
+SetConnectionExtra(dwConnID: CONNID, pExtra: PVOID): BOOL
+GetConnectionExtra(dwConnID: CONNID, ppExtra: PVOID): BOOL
+HasStarted(): BOOL
+GetState(): EnServiceState
+GetMaxConnectionCount(): DWORD
+SetMaxConnectionCount(dwMaxConnectionCount: DWORD): void
+GetConnectionCount(): DWORD
+GetAllConnectionIDs(pIDs: CONNID, dwCount: DWORD): BOOL
+GetConnectPeriod(dwConnID: CONNID, dwPeriod: DWORD): BOOL
+GetSilencePeriod(dwConnID: CONNID, dwPeriod: DWORD): BOOL
+GetLocalAddress(dwConnID: CONNID, lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetRemoteAddress(dwConnID: CONNID, lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetLastError(): EnSocketError
+GetLastErrorDesc(): LPCTSTR
+GetPendingDataLength(dwConnID: CONNID, iPending: int): BOOL
+SetReuseAddressPolicy(enReusePolicy: EnReuseAddressPolicy): void
+SetSendPolicy(enSendPolicy: EnSendPolicy): void
+SetMarkSilence(bMarkSilence: BOOL): void
+IsMarkSilence(): BOOL
+SetFreeSocketObjLockTime(dwFreeSocketObjLockTime: DWORD): void
+SetFreeSocketObjPool(dwFreeSocketObjPool: DWORD): void
+SetFreeBufferObjPool(dwFreeBufferObjPool: DWORD): void
+SetFreeSocketObjHold(dwFreeSocketObjHold: DWORD): void
+SetFreeBufferObjHold(dwFreeBufferObjHold: DWORD): void
+SetWorkerThreadCount(dwWorkerThreadCount: DWORD): void
+GetReuseAddressPolicy(): EnReuseAddressPolicy
+GetSendPolicy(): EnSendPolicy
+GetFreeSocketObjLockTime(): DWORD
+GetFreeSocketObjPool(): DWORD
+GetFreeBufferObjPool(): DWORD
+GetFreeSocketObjHold(): DWORD
+GetFreeBufferObjHold(): DWORD
+GetWorkerThreadCount(): DWORD
<<destroy>>-IComplexSocket()
IPullSocket
+Fetch(dwConnID: CONNID, pData: BYTE, iLength: int): EnFetchResult
+Peek(dwConnID: CONNID, pData: BYTE, iLength: int): EnFetchResult
<<destroy>>-IPullSocket()
IPackSocket
+SetMaxPackSize(dwMaxPackSize: DWORD): void
+SetPackHeaderFlag(usPackHeaderFlag: USHORT): void
+GetMaxPackSize(): DWORD
+GetPackHeaderFlag(): USHORT
<<destroy>>-IPackSocket()
ITcpPackServer
+ToPack(pServer: IServer): IPackSocket
+ToServer(pPackSocket: IPackSocket): ITcpServer
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
24
2.2.1-2 Server 监听器接口
Server 组件接口的继承层次结构如图 2.2.1-1 示,其中,ITcpServer IUdpServer 继承
IServerITcpPullServer ITcpPackServer 则继承 ITcpServer。主要接口方法如表 2.2.1-
1 所示,其它接口方法请参考 include/hpsocket/SocketInterface.h 文件的相关注释:
组件接口
操作方法
IServer
Start()
启动组件
Stop()
关闭组件
Send()
发送数据
SendPackets()
发送多组数据
Disconnect()
断开连接
DisconnectLongConnections()
断开长连接
DisconnectSilenceConnections()
断开静默连接
PauseReceive()
暂停接收数据
IsConnected()
检测是否有效连
HasStarted()
检查通信组件是否已启动
GetState()
获取通信组件当前状态
GetConnectionCount()
获取连接数
GetConnectPeriod()
获取连接时长
GetSilencePeriod()
获取静默时长
IComplexSocketListenerT<T>
+OnShutdown(pSender: T): EnHandleResult
IServerListenerT<T>
+OnPrepareListen(pSender: T, soListen: SOCKET): EnHandleResult
+OnAccept(pSender: T, dwConnID: CONNID, soClient: SOCKET): EnHandleResult
IUdpServerListenerITcpServerListener
ISocketListenerT<T>
+OnHandShake(pSender: ITcpClient, dwConnID: CONNID): EnHandleResult
+OnSend(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, iLength: int): EnHandleResult
+OnClose(pSender: T, dwConnID: CONNID, enOperation: EnSocketOperation, iErrorCode: int): EnHandleResult
<<destroy>>-ISocketListenerT()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
25
GetAllConnectionIDs()
获取所有连接 CONNID
GetLocalAddress()
获取某个连接的本地地址
GetRemoteAddress()
获取某个连接的远程地址
GetListenAddress()
获取监听 Socket 的地址
GetLastError()
获取最近一次失败操作的错误代码
GetLastErrorDesc()
获取最近一次失败操作的错误描述
SetWorkerThreadCount()
设置工作线程数
SetMaxConnectionCount()
设置最大连接数
ITcpServer
SendSmallFile()
发送小文件
SetSocketListenQueue()
设置监听 Socket 的等候队列大小
SetAcceptSocketCount()
Windows设置 Accept 预投递数
Linux:设置 EPOLL 事件最大数量
SetSocketBufferSize()
设置通信数据缓冲区大小
SetKeepAliveTime()
设置心跳检测包发送间隔
SetKeepAliveInterval()
设置心跳检测重试包发送间隔
SetNoDelay()
设置 TCP_NODELAY Socket 选项
ITcpPullServer
Fetch()
拉取数据
Peek()
窥探数据
ITcpPackServer
SetMaxPackSize()
设置最大包长限
SetPackHeaderFlag()
设置包头校验标
IUdpServer
SetMaxDatagramSize()
设置数据报文最大长度
SetDetectAttempts()
设置检测重试次数
SetDetectInterval()
设置检测包发送间隔
IUdpArqServer
SetMaxMessageSize()
设置 ARQ 数据报文最大长
SetHandShakeTimeout()
设置 ARQ 握手超时时间
2.2.1-1 Server 组件接口
Server 2.2.1-2 ITcpServerListener
IUdpServerListener 继承 IServerListener,接口回调事件如表 2.2.1-2 所示
监听器接口
回调事件
ISocketListenerT
OnHandShake()
握手完成
握手完成时触发
OnSend()
数据已发送
数据发送成功后触发
OnReceive() [PUSH]
数据到达(PUSH / PACK
接收到数据时触
OnReceive() [PULL]
数据到达(PULL
接收到数据时触
OnClose()
连接关闭
连接正常或异常关闭时触
IComplexSocketListenerT
OnShutdown()
关闭通信组件
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
26
通信组件停止后触发
IServerListenerT
OnPrepareListen()
准备监听
绑定监听地址前触发
OnAccept()
接受连接请求
客户端连接请求到达时触
2.2.1-2 Server 监听器接口
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
27
2.2.2 工作流程
2.2.2-1 Server 工作流程
2.2.2-1 展示了服务端、客户端应用程序 Server 组件的交互流程:
服务端应用程序调用 Start() 方法启动 Server 组件,如果调用成功则返回 TRUE
Server Application Server Component Client Application
IServer := new(listener)
<<create>>
server
Start()
OnPrepareListen
OnAccept Connect
OnHandshake
OnReceive Send
Send()
OnSend
Send
OnClose Disconnect
Disconnect()
OnClose
Disconnect
Stop()
OnShutdown
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
28
收到 OnPrepareListen 事件。
OnAccept OnHandshake 事件。
客户端应用程序向服务端应用程序发送数据时,服务端应用程序将收到 OnReceive
事件。
服务端应用程序调用 Send() 方法向客户端应用程序发出数据后,服务端应用程序
将收到 OnSend 事件。
断开连接时,服务端应用程序将收 OnClose 事件。
服务端应用程序调用 Stop() 方法关闭 Server 组件,如果调用成功则返回 TRUE
收到 OnShutdown 事件
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
29
2.3 Agent 组件
2.3.1 接口描述
2.3.1-1 Agent 组件接口
IComplexSocket
+Stop(): BOOL
+Wait(dwMilliseconds: DWORD): BOOL
+Send(dwConnID: CONNID, pBuffer: BYTE, iLength: int, iOffset: int): BOOL
+SendPackets(dwConnID: CONNID, pBuffers: WSABUF, iCount: int): BOOL
+Disconnect(dwConnID: CONNID, bForce: BOOL): BOOL
+DisconnectLongConnections(dwPeriod: DWORD, bForce: BOOL): BOOL
+DisconnectSilenceConnections(dwPeriod: DWORD, bForce: BOOL): BOOL
+PauseReceive(dwPeriod: DWORD, bPause: BOOL): BOOL
+IsPauseReceive(dwPeriod: DWORD, bPaused: BOOL): BOOL
+IsSecure(): BOOL
+IsConnected(dwConnID: CONNID): BOOL
+SetConnectionExtra(dwConnID: CONNID, pExtra: PVOID): BOOL
+GetConnectionExtra(dwConnID: CONNID, ppExtra: PVOID): BOOL
+HasStarted(): BOOL
+GetState(): EnServiceState
+GetMaxConnectionCount(): DWORD
+SetMaxConnectionCount(dwMaxConnectionCount: DWORD): void
+GetConnectionCount(): DWORD
+GetAllConnectionIDs(pIDs: CONNID, dwCount: DWORD): BOOL
+GetConnectPeriod(dwConnID: CONNID, dwPeriod: DWORD): BOOL
+GetSilencePeriod(dwConnID: CONNID, dwPeriod: DWORD): BOOL
+GetLocalAddress(dwConnID: CONNID, lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetRemoteAddress(dwConnID: CONNID, lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetLastError(): EnSocketError
+GetLastErrorDesc(): LPCTSTR
+GetPendingDataLength(dwConnID: CONNID, iPending: int): BOOL
+SetReuseAddressPolicy(enReusePolicy: EnReuseAddressPolicy): void
+SetSendPolicy(enSendPolicy: EnSendPolicy): void
+SetMarkSilence(bMarkSilence: BOOL): void
+IsMarkSilence(): BOOL
+SetFreeSocketObjLockTime(dwFreeSocketObjLockTime: DWORD): void
+SetFreeSocketObjPool(dwFreeSocketObjPool: DWORD): void
+SetFreeBufferObjPool(dwFreeBufferObjPool: DWORD): void
+SetFreeSocketObjHold(dwFreeSocketObjHold: DWORD): void
+SetFreeBufferObjHold(dwFreeBufferObjHold: DWORD): void
+SetWorkerThreadCount(dwWorkerThreadCount: DWORD): void
+GetReuseAddressPolicy(): EnReuseAddressPolicy
+GetSendPolicy(): EnSendPolicy
+GetFreeSocketObjLockTime(): DWORD
+GetFreeSocketObjPool(): DWORD
+GetFreeBufferObjPool(): DWORD
+GetFreeSocketObjHold(): DWORD
+GetFreeBufferObjHold(): DWORD
+GetWorkerThreadCount(): DWORD
<<destroy>>-IComplexSocket()
IA gent
+Start(lpszBindAddress: LPCTSTR, pdwConnID: PCONNID, bAsyncConnect: BOOL, pExtra: PVOID, usLocalPort: USHORT): BOOL
+Connect(lpszRemoteAddress: LPCTSTR, usPort: USHORT, pdwConnID: CONNID, pExtra: PVOID, usLocalPort: USHORT, lpszLocalAddress: LPCTSTR): BOOL
+GetRemoteHost(dwConnID: CONNID, lpszHost: TCHAR, iHostLen: int, usPort: USHORT): BOOL
ITcpAgent
+SendSmallFile(dwConnID: CONNID, lpszFileName: LPCTSTR, pHead: LPWSABUF, pTail: LPWSABUF): BOOL
+SetSocketBufferSize(dwSocketBufferSize: DWORD): void
+SetKeepAliveTime(dwKeepAliveTime: DWORD): void
+SetKeepAliveInterval(dwKeepAliveInterval: DWORD): void
+GetSocketBufferSize(): DWORD
+GetKeepAliveTime(): DWORD
+GetKeepAliveInterval(): DWORD
IPullSocket
+Fetch(dwConnID: CONNID, pData: BYTE, iLength: int): EnFetchResult
+Peek(dwConnID: CONNID, pData: BYTE, iLength: int): EnFetchResult
<<destroy>>-IPullSocket()
ITcpPullAgent
+ToPull(pAgent: IAgent): IPullSocket
+ToAgent(pPullSocket: IPullSocket): ITcpAgent
IPackSocket
+SetMaxPackSize(dwMaxPackSize: DWORD): void
+SetPackHeaderFlag(usPackHeaderFlag: USHORT): void
+GetMaxPackSize(): DWORD
+GetPackHeaderFlag(): USHORT
<<destroy>>-IPackSocket()
ITcpPackAgent
+ToPack(pAgent: IAgent): IPackSocket
+ToAgent(pPackSocket: IPackSocket): ITcpAgent
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
30
2.3.1-2 Agent 监听器接
Agent 组件接口的继承层次结构如 2.3.1-1 所示,其中,ITcpAgent 继承于 IAgent
ITcpPullAgent ITcpPackAgent 则继承于 ITcpAgent。主要接口方法如表 2.3.1-1 所示,其它
接口方法请参 include/hpsocket/SocketInterface.h 文件的相关注释:
组件接口
操作方法
IAgent
Start()
启动组件
Stop()
关闭组件
Connect()
连接服务器
Send()
发送数据
SendPackets()
发送多组数据
Disconnect()
断开连接
DisconnectLongConnections()
断开长连接
DisconnectSilenceConnections()
断开静默连接
PauseReceive()
暂停接收数据
IsConnected()
检测是否有效连
HasStarted()
检查通信组件是否已启动
GetState()
获取通信组件当前状态
GetConnectionCount()
获取连接数
GetConnectPeriod()
获取连接时长
GetSilencePeriod()
获取静默时长
GetAllConnectionIDs()
获取所有连接 CONNID
IComplexSocketListenerT<T>
+OnShutdown(pSender: T): EnHandleResult
IAgentListenerT<T>
+OnPrepareConnect(pSender: T, dwConnID: CONNID, socket: SOCKET): EnHandleResult
+OnConnect(pSender: T, dwConnID: CONNID): EnHandleResult
ITcpAgentListener
ISocketListenerT<T>
+OnHandShake(pSender: ITcpClient, dwConnID: CONNID): EnHandleResult
+OnSend(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, iLength: int): EnHandleResult
+OnClose(pSender: T, dwConnID: CONNID, enOperation: EnSocketOperation, iErrorCode: int): EnHandleResult
<<destroy>>-ISocketListenerT()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
31
GetLocalAddress()
获取某个连接的本地地址
GetRemoteHost()
获取某个连接的远程主机
GetLastError()
获取最近一次失败操作的错误代码
GetLastErrorDesc()
获取最近一次失败操作的错误描述
SetWorkerThreadCount()
设置工作线程数
SetMaxConnectionCount()
设置最大连接数
ITcpAgent
SendSmallFile()
发送小文件
SetReuseAddress()
设置是否启用地址重用机
SetSocketBufferSize()
设置通信数据缓冲区大小
SetKeepAliveTime()
设置心跳检测包发送间隔
SetKeepAliveInterval()
设置心跳检测重试包发送间隔
SetNoDelay()
设置 TCP_NODELAY Socket 选项
ITcpPullAgent
Fetch()
拉取数据
Peek()
窥探数据
ITcpPackAgent
SetMaxPackSize()
设置最大包长限
SetPackHeaderFlag()
设置包头校验标
2.3.1-1 Agent 组件接口
Agent 监听器接口的继承层次结构如 2.3.1-2 所示,其中,ITcpAgentListener 继承于
IAgentListener,接口回调事件如表 2.3.1-2 所示:
监听器接口
回调事件
ISocketListenerT
OnHandShake()
握手完成
握手完成时触发
OnSend()
数据已发送
数据发送成功后触发
OnReceive() [PUSH]
数据到达(PUSH / PACK
接收到数据时触
OnReceive() [PULL]
数据到达(PULL
接收到数据时触
OnClose()
连接关闭
连接正常或异常关闭时触
IComplexSocketListenerT
OnShutdown()
关闭通信组件
通信组件停止后触发
IAgentListenerT
OnPrepareConnect()
准备建立连接
建立连接前触发
OnConnect()
成功建立连接
成功建立连接后触发
2.3.1-2 Agent 监听器接
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
32
2.3.2 工作流程
2.3.2-1 Agent 工作流程
Client Application Agent Component Server Application
IAgent := new(listener)
<<create>>
agent
Start()
Connect()
OnPrepareConnect
Connect
OnConnect
OnHandshake
Send()
OnSend
Send
OnReceive Send
OnClose Disconnect
Disconnect()
Disconnect
OnClose
Stop()
OnShutdown
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
33
2.3.2-1 展示了服务端、客户端应用程序 Agent 组件的交互流程
客户端应用程序调用 Start() 方法启动 Agent 组件,如果调用成功则返回 TRUE
客户端应用程序调用 Connect() 方法向服务端应用程序发起连接请求,如果连接成
功则返回 TRUE 并且会先后接收到 OnPrepareConnectOnConnect OnHandshake
事件。
客户端应用程序调用 Send() 方法向服务端应用程序发出数据后,客户端应用程序
将收到 OnSend 事件。
服务端应用程序客户端应用程序发送数据时客户端应用程序将收到 OnReceive
事件。
断开连接时,客户端应用程序将收 OnClose 事件。
客户端应用程序调用 Stop() 方法关闭 Agent 组件,如果调用成功则返 TRUE
收到 OnShutdown 事件
2.4 Client 组件
2.4.1 接口描述
2.4.1-1 Client 组件接口
IClient
+Start(lpszRemoteAddress: LPCTSTR, usPort: USHORT, bAsyncConnect: BOOL, lpszBindAddress: LPCTSTR, usLocalPort: USHORT): BOOL
+Stop(): BOOL
+Wait(dwMilliseconds: DWORD): BOOL
+Send(pBuffer: BYTE, iLength: int, iOffset: int): BOOL
+SendPackets(pBuffers: WSABUF, iCount: int): BOOL
+PauseReceive(bPause: BOOL): BOOL
+IsPauseReceive(bPaused: BOOL): BOOL
+IsSecure(): BOOL
+IsConnected(): BOOL
+SetExtra(pExtra: PVOID): void
+GetExtra(): PVOID
+HasStarted(): BOOL
+GetState(): EnServiceState
+GetLastError(): EnSocketError
+GetLastErrorDesc(): LPCTSTR
+GetConnectionID(): CONNID
+GetLocalAddress(lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
+GetRemoteHost(lpszHost: TCHAR, iHostLen: int, usPort: USHORT): BOOL
+GetFreeBufferPoolSize(): DWORD
+GetPendingDataLength(iPending: int): BOOL
+SetFreeBufferPoolSize(dwFreeBufferPoolSize: DWORD): void
+SetFreeBufferPoolHold(dwFreeBufferPoolHold: DWORD): void
+GetFreeBufferPoolHold(): DWORD
+SetReuseAddressPolicy(enReusePolicy: EnReuseAddressPolicy): void
+GetReuseAddressPolicy(): EnReuseAddressPolicy
<<destroy>>-IClient()
ITcpClient
+SendSmallFile(lpszFileName: LPCTSTR, pHead: LPWSABUF, pTail: LPWSABUF): BOOL
+SetSocketBufferSize(dwSocketBufferSize: DWORD): void
+SetKeepAliveTime(dwKeepAliveTime: DWORD): void
+SetKeepAliveInterval(dwKeepAliveInterval: DWORD): void
+GetSocketBufferSize(): DWORD
+GetKeepAliveTime(): DWORD
+GetKeepAliveInterval(): DWORD
IUdpClient
+SetMaxDatagramSize(dwMaxDatagramSize: DWORD): void
+GetMaxDatagramSize(): DWORD
+SetDetectAttempts(dwDetectAttempts: DWORD): void
+SetDetectInterval(dwDetectInterval: DWORD): void
+GetDetectAttempts(): DWORD
+GetDetectInterval(): DWORD
IUdpCast
+SetMaxDatagramSize(dwMaxDatagramSize: DWORD): void
+GetMaxDatagramSize(): DWORD
+SetCastMode(enCastMode: EnCastMode): void
+GetCastMode(): EnCastMode
+SetMultiCastTtl(iMCTtl: int): void
+GetMultiCastTtl(): int
+SetMultiCastLoop(bMCLoop: BOOL): void
+IsMultiCastLoop(): BOOL
+GetRemoteAddress(lpszAddress: TCHAR, iAddressLen: int, usPort: USHORT): BOOL
IPullClient
+Fetch(pData: BYTE, iLength: int): EnFetchResult
+Peek(pData: BYTE, iLength: int): EnFetchResult
<<destroy>>-IPullClient()
ITcpPullClient
+ToPull(pClient: IClient): IPullClient
+ToClient(pPullClient: IPullClient): ITcpClient
IPackClient
+SetMaxPackSize(dwMaxPackSize: DWORD): void
+SetPackHeaderFlag(usPackHeaderFlag: USHORT): void
+GetMaxPackSize(): DWORD
+GetPackHeaderFlag(): USHORT
<<destroy>>-IPackClient()
ITcpPackClient
+ToPack(pClient: IClient): IPackClient
+ToClient(pPackClient: IPackClient): ITcpClient
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
34
2.4.1-2 Client 监听器接口
Client 组件接口的继承层次结构如图 2.4.1-1 示,ITcpClientIUdpClient
IUdpCast 继承于 IClientITcpPullClient ITcpPackClient 则继承于 ITcpClient。主要接口方
法如表 2.4.1-1 所示,其它接口方法请参考 include/hpsocket/SocketInterface.h 文件的相关注释:
组件接口
操作方法
IClient
Start()
启动组件
Stop()
关闭组件
Connect()
连接服务器
Send()
发送数据
SendPackets()
发送多组数据
PauseReceive()
暂停接收数据
IsConnected()
检测是否有效连
HasStarted()
检查通信组件是否已启动
GetState()
获取通信组件当前状态
GetConnectionID()
获取该组件对象 CONNID
GetLocalAddress()
获取连接的本地地址
GetRemoteHost()
获取连接的远程主机
GetLastError()
获取最近一次失败操作的错误代码
GetLastErrorDesc()
获取最近一次失败操作的错误描述
ITcpClient
SendSmallFile()
发送小文件
SetSocketBufferSize()
设置通信数据缓冲区大小
SetKeepAliveTime()
设置心跳检测包发送间隔
IClientListenerT<T>
+OnPrepareConnect(pSender: T, dwConnID: CONNID, socket: SOCKET): EnHandleResult
+OnConnect(pSender: T, dwConnID: CONNID): EnHandleResult
ITcpClientListener IUdpCastListenerIUdpClientListener
ISocketListenerT<T>
+OnHandShake(pSender: ITcpClient, dwConnID: CONNID): EnHandleResult
+OnSend(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, pData: BYTE, iLength: int): EnHandleResult
+OnReceive(pSender: T, dwConnID: CONNID, iLength: int): EnHandleResult
+OnClose(pSender: T, dwConnID: CONNID, enOperation: EnSocketOperation, iErrorCode: int): EnHandleResult
<<destroy>>-ISocketListenerT()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
35
SetKeepAliveInterval()
设置心跳检测重试包发送间隔
SetNoDelay()
设置 TCP_NODELAY Socket 选项
ITcpPullClient
Fetch()
拉取数据
Peek()
窥探数据
ITcpPackClient
SetMaxPackSize()
设置最大包长限
SetPackHeaderFlag()
设置包头校验标
IUdpClient
SetMaxDatagramSize()
设置数据报文最大长度
SetDetectAttempts()
设置检测重试次数
SetDetectInterval()
设置检测包发送间隔
IUdpArqClient
SetMaxMessageSize()
设置 ARQ 数据报文最大长
SetHandShakeTimeout()
设置 ARQ 握手超时时间
IUdpCast
SetMaxDatagramSize()
设置数据报文最大长度
SetReuseAddress()
设置是否启用地址重用机
SetCastMode()
设置传播模式(组播或广播)
SetMultiCastTtl()
设置组播报文 TTL
SetMultiCastLoop()
设置是否启用组播环路
GetRemoteAddress()
获取当前数据包的远程地
2.4.1-1 Client 组件接口
Client 2.4.1-2 ITcpClientListener
IUdpClientListener 承于 IClientListener,接口回调事件如 2.4.1-2 所示
监听器接口
回调事件
ISocketListenerT
OnHandShake()
握手完成
握手完成时触发
OnSend()
数据已发送
数据发送成功后触发
OnReceive() [PUSH]
数据到达(PUSH / PACK
接收到数据时触
OnReceive() [PULL]
数据到达(PULL
接收到数据时触
OnClose()
连接关闭
连接正常或异常关闭时触
IClientListenerT
OnPrepareConnect()
准备建立连接
建立连接前触发
OnConnect()
成功建立连接
成功建立连接后触发
2.4.1-2 Client 监听器接口
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
36
2.4.2 工作流程
2.4.2-1 Client 工作流程
2.4.2-1 展示了服务端、客户端应用程序 Client 组件的交互流程
客户端应用程序调用 Start() 方法向服务端应用程序发起连接请求,如果连接成功
则返回 TRUE 并且会先后接收到 OnPrepareConnectOnConnect OnHandshake
件。
Client Application Server ApplicationClient Component
IClient := new(listener)
<<create>>
client
Start()
OnPrepareConnect
OnConnect
OnHandShake
Send()
OnSend
Send
OnReceive Send
OnClose Disconnect
Stop()
OnClose
Disconnect
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
37
客户端应用程序调用 Send() 方法向服务端应用程序发出数据后,客户端应用程序
将收到 OnSend 事件。
服务端应用程序向客户端应用程序发送数据时,客户端应用程序将收到 OnReceive
事件。
断开连接时,客户端应用程序将收 OnClose 事件。
客户端应用程序调用 Stop() 方法关闭 Client 组件,如果调用成功则返 TRUE
收到 OnClose 件。
2.5 UDP Node 组件
2.5.1 接口描述
2.5.1-1 UDP Node 组件接口
IUdpNode
+Start()
+Stop()
+Wait()
+Send()
+SendPackets()
+SendCast()
+SendCastPackets()
+SetExtra()
+GetExtra()
+HasStarted()
+GetState()
+GetLastError()
+GetLastErrorDesc()
+GetLocalAddress()
+GetCastAddress()
+GetCastMode()
+GetPendingDataLength()
+SetMaxDatagramSize()
+GetMaxDatagramSize()
+SetMultiCastTtl()
+GetMultiCastTtl()
+SetMultiCastLoop()
+IsMultiCastLoop()
+SetReuseAddressPolicy()
+GetReuseAddressPolicy()
+SetWorkerThreadCount()
+GetWorkerThreadCount()
+SetPostReceiveCount()
+GetPostReceiveCount()
+SetFreeBufferPoolSize()
+GetFreeBufferPoolSize()
+SetFreeBufferPoolHold()
+GetFreeBufferPoolHold()
<<destroy>>+IUdpNode()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
38
2.5.1-2 UDP Node 监听器接口
HP-Socket v5.7.x 版本开始,提供 UDP NodeUDP 节点)组件:IUdpNodeUDP Node
HP-Socket 的其它通信组件不同,它没有“连接”的概念(因此也没有 Connection ID
行为模式类似于普通 UDP Socket可以同时与任何 UDP 应用程序通信。该组件可以以单播
组播和广播三种模式运行UDP Node 组件接口如 2.5.1-1 所示是一个独立的接口,继承
于其它任何接口 2.5.1-1
include/hpsocket/SocketInterface.h 件的相关注释:
组件接口
操作方法
IUdpNode
Start()
启动组件
Stop()
关闭组件
Send()
向指定目标地址发送数据
SendPackets()
向指定目标地址发送组合数据
SendCast()
发送组播或广播数据
SendCastPackets()
发送组播或广播组合数据
SetMaxDatagramSize()
设置数据报文最大长度
HasStarted()
检查通信组件是否已启动
GetState()
获取通信组件当前状态
GetLocalAddress()
获取连接的本地地址
GetCastAddress()
获取关联的组播或广播地
GetLastError()
获取最近一次失败操作的错误代码
GetLastErrorDesc()
获取最近一次失败操作的错误描述
2.5.1-1 UDP Node 组件接
UDP Node 监听器接口如 2.5.1-2 所示也是一个独立的接口,不继承于其它任何接口。
接口回调事件如 2.5.1-2 所示:
监听器接口
回调事件
IUdpNodeListener
OnPrepareListen()
准备监听
绑定监听地址前触发
OnSend()
数据已发送
数据发送成功后触发
OnReceive()
数据到达
接收到数据时触
IUdpNodeListener
+OnPrepareListen()
+OnSend()
+OnReceive()
+OnError()
+OnShutdown()
<<destroy>>+IUdpNodeListener()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
39
OnError()
数据收发失败
接收或发送数据失败时触
OnShutdown()
关闭通信组件
通信组件停止后触发
2.5.1-2 UDP Node 监听器接口
2.5.2 工作流程
2.5.2-1 UDP Node 工作流
2.5.2-1 展示了应用程序 UDP Node 组件的交互流程:
应用程序调用 Start() 方法启动 UDP Node 组件,如果调用成功则返 TRUE 并收
OnPrepareListen 件。
应用程序调用 Send()SendCast() 等方法发送单播组播或广播数据数据发出后
Node Application Remote ApplicationUDP Node Component
IUdpNode := new(listener)
<<create>>
node
Start()
OnPrepareListen
Send()
OnSend
Send
OnReceive Send
OnError
Stop()
OnShutdown
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
40
应用程序将收 OnSend 事件。
远程应用程序向应用程序发送数据时,应用程序将收到 OnReceive 事件
数据发送或接收出现异常时,应用程序将收 OnError 事件。
应用程序调用 Stop() 方法关闭 UDP Node 组件,如果调用成功则返回 TRUE 并收
OnShutdown 事件。
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
41
3 SSL
3.1 组件接口
HP-Socket v3.5.x 版本开始所有 TCP 组件全面支 SSLSSL 组件与对应的非 SSL
件实现相同的接口,它们的使用方式也一致。 3.1-1 列出了所有 SSL 组件的名称、接口
监听器接口、实现类及其分类:
Name
Component Intface
Listener Intface
Implement Class
Role
Protocol
SSL Server
ITcpServer
ITcpServerListener
CSSLServer
Server
PUSH
SSL Pull Server
ITcpPullServer
ITcpServerListener
CSSLPullServer
Server
PULL
SSL Pack Server
ITcpPackServer
ITcpServerListener
CSSLPackServer
Server
PACK
SSL Agent
ITcpAgent
ITcpServerListener
CSSLAgent
Client
PUSH
SSL Pull Agent
ITcpPullAgent
ITcpAgentListener
CSSLPullAgent
Client
PULL
SSL Pack Agent
ITcpPackAgent
ITcpServerListener
CSSLPackAgent
Client
PACK
SSL Client
ITcpClient
ITcpClientListener
CSSLClient
Client
PUSH
SSL Pull Client
ITcpPullClient
ITcpClientListener
CSSLPullClient
Client
PULL
SSL Pack Client
ITcpPackClient
ITcpClientListener
CSSLPackClient
Client
PACK
3.1-1 组件分
SSL 组件的层次结构如 3.1-1 所示,所 SSL 组件都继承于对应 TCP 组件:
CSSLServer >> CTcpServer
CSSLAgent >> CTcpAgent
CSSLClient >> CTcpClient
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
42
3.1-1 组件层次结构
IPullSocket
+Fetch()
+Peek()
<<destroy>>-IPullSocket()
CTcpAgentCTcpServer
IPackSocket
+SetMaxPackSize()
+SetPackHeaderFlag()
+GetMaxPackSize()
+GetPackHeaderFlag()
<<destroy>>-IPackSocket()
CSSLServer
+SetupSSLContext()
+SetupSSLContextByMemory()
+AddSSLContext()
+AddSSLContextByMemory()
+CleanupSSLContext()
+SendPackets()
+StartSSLHandShake()
+SetSSLAutoHandShake()
+IsSSLAutoHandShake()
+SetSSLCipherList()
+GetSSLCipherList()
+GetSSLSessionInfo()
+IsSecuer()
<<create>>-CSSLServer()
<<destroy>>-CSSLServer()
CSSLPullServer
+Fetch()
+Peek()
<<create>>-CSSLPullServer()
<<destroy>>-CSSLPullServer()
CSSLPullAgent
+Fetch()
+Peek()
<<create>>-CSSLPullAgent()
<<destroy>>-CSSLPullAgent()
CSSLPackServer
+SendPackets()
+SetMaxPackSize()
+SetPackHeaderFlag()
+GetMaxPackSize()
+GetPackHeaderFlag()
+FireSuperReceive()
<<create>>-CSSLPackServer()
<<destroy>>-CSSLPackServer()
CSSLPackAgent
+SendPackets()
+SetMaxPackSize()
+SetPackHeaderFlag()
+GetMaxPackSize()
+GetPackHeaderFlag()
+FireSuperReceive()
<<create>>-CSSLPackAgent()
<<destroy>>-CSSLPackAgent()
CSSLAgent
+SetupSSLContext()
+SetupSSLContextByMemory()
+CleanupSSLContext()
+SendPackets()
+StartSSLHandShake()
+SetSSLAutoHandShake()
+IsSSLAutoHandShake()
+SetSSLCipherList()
+GetSSLCipherList()
+GetSSLSessionInfo()
+IsSecuer()
<<create>>-CSSLAgent()
<<destroy>>-CSSLAgent()
CTcpClient
CSSLClient
+SetupSSLContext()
+SetupSSLContextByMemory()
+CleanupSSLContext()
+SendPackets()
+StartSSLHandShake()
+SetSSLAutoHandShake()
+IsSSLAutoHandShake()
+SetSSLCipherList()
+GetSSLCipherList()
+GetSSLSessionInfo()
+IsSecuer()
<<create>>-CSSLClient()
<<destroy>>-CSSLClient()
IPackClient
+SetMaxPackSize()
+SetPackHeaderFlag()
+GetMaxPackSize()
+GetPackHeaderFlag()
<<destroy>>-IPackClient()
IPullClient
+Fetch()
+Peek()
<<destroy>>-IPullClient()
CSSLPullClient
+Fetch()
+Peek()
<<create>>-CSSLPullClient()
<<destroy>>-CSSLPullClient()
CSSLPackClient
+SendPackets()
+SetMaxPackSize()
+SetPackHeaderFlag()
+GetMaxPackSize()
+GetPackHeaderFlag()
+FireSuperReceive()
<<create>>-CSSLPackClient()
<<destroy>>-CSSLPackClient()
EnSSLSessionMode
<<enumeration>>
+SSL_SM_CLIENT
+SSL_SM_SERVER
EnSSLVerifyMode
<<enumeration>>
+SSL_VM_NONE
+SSL_VM_PEER
+SSL_VM_FAIL_IF_NO_PEER_CERT
+SSL_VM_CLIENT_ONCE
Fn_SNI_ServerNameCallback
<<CppTypedef>>
+__HP_CALL(lpszServerName: LPCTSTR, pContext: PVOID): int
EnSSLSessionInfo
<<enumeration>>
+SSL_SSI_MIN
+SSL_SSI_CTX
+SSL_SSI_CTX_METHOD
+SSL_SSI_CTX_CIPHERS
+SSL_SSI_CTX_CERT_STORE
+SSL_SSI_SERVER_NAME_TYPE
+SSL_SSI_SERVER_NAME
+SSL_SSI_VERSION
+SSL_SSI_METHOD
+SSL_SSI_CERT
+SSL_SSI_PKEY
+SSL_SSI_CURRENT_CIPHER
+SSL_SSI_CIPHERS
+SSL_SSI_CLIENT_CIPHERS
+SSL_SSI_PEER_CERT
+SSL_SSI_PEER_CERT_CHAIN
+SSL_SSI_VERIFIED_CHAIN
+SSL_SSI_MAX
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
43
3.2 SSL 运行环境
SSL 组件在启动通信前需要初始化 SSL 环境参数,通信完毕时需要清理 SSL 运行环境。
HP-Socket v4.x.x 及其之前的版本使用全局唯一 SSL 运行环境,所有 SSL 组件都共享该环
境, HP_SSL_Initialize() / HP_SSL_AddServerContext() / HP_SSL_Cleanup() /
HP_SSL_IsValid() 等全局函数操作该全局 SSL 环境,HP-Socket v5.0.x 版本开始,每个 SSL
组件使用独立的 SSL 运行环境,因此上述函数已被删除。取而代之SSL 组件提供相应的
实例方法来操作自身的 SSL 运行环境:
设置 SSL 加密套件
VOID SetSSLCipherList(lpszCipherList)
HP-Socket 的默认加密套件 DEFAULT:!aNULL:!eNULL:!SSLv2:!SSLv3如需修改加
密套件(如:启用 SSLv3 用来支持旧应用系统)则需要调用 SetSSLCipherList() 设置所需
加密套件。加密套件详细信息请参 OpenSSL Ciphers 文档。
使
SetupSSLContext[ByMemory]()
AddSSLContext[ByMemory]()
方法前调用
SetSSLCiperList()
设置加密套件。
初始化 SSL 环境参数:
BOOL SetupSSLContext(enSessionMode, iVerifyMode = SSL_VM_NONE,
lpszPemCertFile = nullptr, lpszPemKeyFile = nullptr, lpszKeyPasswod = nullptr,
lpszCAPemCertFileOrPath = nullptr, [fnServerNameCallback = nullptr])
BOOL SetupSSLContextByMemory(enSessionMode, iVerifyMode = SSL_VM_NONE,
lpszPemCert = nullptr, lpszPemKey = nullptr, lpszKeyPasswod = nullptr, lpszCAPemCert =
nullptr, [fnServerNameCallback = nullptr])
参数 iVerifyMode SSL lpszPemCert[File]lpszPemKey[File]
lpszKeyPasswod lpszCAPemCert[FileOrPath] 分别指定证书文件、私钥文件、私钥密码
CA 证书文件/目录参数 fnServerNameCallback 只用于 HTTPS 服务端,此参数指定 SNI
调函数指针,如果此参数值 nullptr 使用 HP-Socket 默认 SNI 回调函数
HP_SSL_DefaultServerNameCallback(lpszServerName, pContext)该默认 SNI 回调函数根据
BindSSLServerName(lpszServerName, iContextIndex) 设置的域名-证书绑定关系查找证书,如
果找不到则使用默认证书。初始化成功返回 TRUE,失败返回 FALSE,初始化失败可通过
SYS_GetLastError() 获取错误代码(参数详细说明请参考 include/hpsocket/HPSocket-SSL.h
include/hpsocket/HPSocket4C-SSL.h 头文件)
增加 SNI 主机证书(SSL Server 组件)
int AddSSLContext(iVerifyMode, lpszPemCertFile, lpszPemKeyFile, lpszKeyPasswod =
nullptr, lpszCAPemCertFileOrPath = nullptr)
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
44
int AddSSLContextByMemory(iVerifyMode, lpszPemCert, lpszPemKey, lpszKeyPasswod =
nullptr, lpszCAPemCert = nullptr)
仅用于 SSL Server 组件。参数 iVerifyMode 指定 SSL 验证模式;参数 lpszPemCert[File]
lpszPemKey[File]lpszKeyPasswod lpszCAPemCert[FileOrPath] 分别指定证书文件、私钥
文件、私钥密码和 CA 证书文件/目录。执行成功返回 SNI 主机证书对应的索引,该索引用
于在 SNI 回调函数中定 SNI 主机失败返回-1可通过 SYS_GetLastError() 获取错误
码。
绑定服务器主机域名到 SNI 证书(SSL Server 组件)
BOOL BindSSLServerName(lpszServerName, iContextIndex)
仅用于 SSL Server 组件。把服务器主机域名 lpszServerName 绑定到 iContextIndex 证书
索引,默认证书索引为 0,其他证书索引 AddSSLContext() / AddSSLContextByMemory()
建。绑定失败返 FALSE,可通过 SYS_GetLastError() 获取错误代码。
默认 SNI 回调函数(SSL Server 组件)
int HP_SSL_DefaultServerNameCallback(lpszServerName, pContext)
仅用于 SSL Server 组件。获取服务器主机域名 lpszServerName 对应的证书索引,如果该
主机域名未绑定到任何证书则返回默认证书索 0
注意:服务端应用程序一般在初始化
SSL
运行环境时调用
AddSSLContext[ByMemory]()
加载所有
SNI
主机证书,并调用
BindSSLServerName()
绑定服务器主机域名到相应证书。
SNI
此时
AddSSLContext()
BindSSLServerName()
HP_SSL_DefaultServerNameCallback()
的代码段进行同步处理,
避免由于多线程导致的访问冲突。
获取 SSL 会话信息:
BOOL GetSSLSessionInfo([dwConnID, ]enInfo, lppInfo)
SSL Server Agent 组件需要 dwConnID 参数指定目标连接;参数 enInfo 指定需要获
的信息类型;如果获取成功返回 TRUE,同时 lppInfo 参数保存获取到的信息值。获取失败
返回 FALSE SYS_GetLastError() (参 enInfo 详细
include/hpsocket/HPTypeDef.h 头文件)
清理 SSL 环境:
void CleanupSSLContext()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
45
组件停止通信(调用 Stop())时会自动清理 SSL 环境,因此,应用程序只需调用
SetupSSLContext() 初始化组件的 SSL 环境参数,而不需要手工调用本函数。
清理线程局部 SSL 环境资源(全局函数)
void HP_SSL_RemoveThreadLocalState()
任何一个操作 SSL 的线程,在退出时都需要清理线程的局部环境 SSL 资源,主线程和
HP-Socket 工作线程在通信结束时会自动清理线程局部环 SSL 资源。因此,一般情况下不
必手工调用本函数;特殊情况下,当自定义线程参与 HP-Socket 通信操作(如:通信组件发
送策略为 SP_DIRECT 并且该自定义线程调用了 Send() 方法发送数据)并检查到 SSL 内存
泄漏时,需在每次停止组件时在该自定义线程调用本函数。
3.3 SSL 握手
SSL 组件(包括Https组件默认情况下在建立连接后会立刻开始SSL 握手OnHandShake
事件会紧接着 OnConnect / OnAccept 事件触发)。但在某些场景下需要在启动 SSL 通信前执
行一些前置操作例如:通过代理服务器与目标服务器通信就是其中一个典型场景在此场
景中,必须与代理服务器建立连接后才能开 SSL 通信。
HP-Socket v5.4.2 本开始,提供了对手工启 SSL 手的支持。 SSL 组件的
SetSSLAutoHandShake(FALSE) 方法把组件设置为手工握手模式,在执行完前置操作后调
StartSSLHandShake() 启动 SSL 通信。
手工启动 SSL 握手:
BOOL StartSSLHandShake(dwConnID)
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
46
4 HTTP
4.1 组件接口
HP-Socket v4.0.x 版本开始加入 HTTP 组件。HTTP 组件继承于相应 TCP 组件并增加
HTTP 相关操作方法; HTTP 组件监听器也继承于相应的 TCP 组件监听器并提供 HTTP
关通信事件。 4.1-1 列出了所 HTTP 组件的名称、接口监听器接口实现类及 TCP
件父类:
Name
Component Intface
Listener Intface
Implement Class
Role
Base Class
Http Server
IHttpServer
IHttpServerListener
CHttpServer
Server
CTcpServer
Https Server
IHttpServer
IHttpServerListener
CHttpsServer
Server
CSSLServer
Http Agent
IHttpAgent
IHttpAgentListener
CHttpAgent
Client
CTcpAgent
Https Agent
IHttpAgent
IHttpAgentListener
CHttpsAgent
Client
CSSLAgent
Http Client
IHttpClient
IHttpClientListener
CHttpClient
Client
CTcpClient
Https Client
IHttpClient
IHttpClientListener
CHttpsClient
Client
CSSLClient
Http Sync Client
IHttpSyncClient
IHttpClientListener
CHttpSyncClient
Client
CTcpClient
Https Sync Client
IHttpSyncClient
IHttpClientListener
CHttpsSyncClient
Client
CSSLClient
4.1-1 组件分
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
47
CHttpAgentT<T>
+SendRequest()
+SendLocalFile()
+SendChunkData()
+SendPost()
+SendPut()
+SendPatch()
+SendGet()
+SendDelete()
+SendHead()
+SendTrace()
+SendOptions()
+SendConnect()
+SetLocalVersion()
+GetLocalVersion()
+IsUpgrade()
+IsKeepAlive()
+GetVersion()
+GetContentLength()
+GetContentType()
+GetContentEncoding()
+GetTransferEncoding()
+GetUpgradeType()
+GetParseErrorCode()
+GetHeader()
+GetHeaders()
+GetAllHeaders()
+GetAllHeaderNames()
+GetCookie()
+GetAllCookies()
+SetUseCookie()
+IsUseCookie()
+GetStatusCode()
+SendWSMessage()
+GetWSMessageState()
<<create>>-CHttpAgentT()
<<destroy>>-CHttpAgentT()
CHttpServerT<T>
+Start()
+SendResponse()
+SendLocalFile()
+SendChunkData()
+Release()
+SetLocalVersion()
+SetReleaseDelay()
+GetLocalVersion()
+GetReleaseDelay()
+IsUpgrade()
+IsKeepAlive()
+GetVersion()
+GetHost()
+GetContentLength()
+GetContentType()
+GetContentEncoding()
+GetTransferEncoding()
+GetUpgradeType()
+GetParseErrorCode()
+GetHeader()
+GetHeaders()
+GetAllHeaders()
+GetAllHeaderNames()
+GetCookie()
+GetAllCookies()
+GetUrlFieldSet()
+GetUrlField()
+GetMethod()
+SendWSMessage()
+GetWSMessageState()
<<create>>-CHttpServerT()
<<destroy>>-CHttpServerT()
ITcpServer ITcpAgent
IComplexHttp
+SendChunkData()
+SetLocalVersion()
+GetLocalVersion()
+IsUpgrade()
+IsKeepAlive()
+GetVersion()
+GetContentLength()
+GetContentType()
+GetContentEncoding()
+GetTransferEncoding()
+GetUpgradeType()
+GetParseErrorCode()
+GetHeader()
+GetHeaders()
+GetAllHeaders()
+GetAllHeaderNames()
+GetCookie()
+GetAllCookies()
+GetWSMessageState()
<<destroy>>-IComplexHttp()
IComplexHttpRequester
+SendRequest()
+SendLocalFile()
+SendPost()
+SendPut()
+SendPatch()
+SendGet()
+SendDelete()
+SendHead()
+SendTrace()
+SendOptions()
+SendConnect()
+SendWSMessage()
+GetStatusCode()
+SetUseCookie()
+IsUseCookie()
IComplexHttpResponder
+SendResponse()
+SendLocalFile()
+SendWSMessage()
+Release()
+SetReleaseDelay()
+GetReleaseDelay()
+GetUrlFieldSet()
+GetUrlField()
+GetMethod()
+GetHost()
CHttpAgent
<<CppTypedef>>
CHttpsAgent
<<CppTypedef>>
CHttpServer
<<CppTypedef>>
CHttpsServer
<<CppTypedef>>
IHttpServer
<<CppTypedef>>
IHttpAgent
<<CppTypedef>>
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
48
CHttpClientT<T>
+SendRequest()
+SendLocalFile()
+SendChunkData()
+SendPost()
+SendPut()
+SendPatch()
+SendGet()
+SendDelete()
+SendHead()
+SendTrace()
+SendOptions()
+SendConnect()
+SetLocalVersion()
+GetLocalVersion()
+IsUpgrade()
+IsKeepAlive()
+GetVersion()
+GetContentLength()
+GetContentType()
+GetContentEncoding()
+GetTransferEncoding()
+GetUpgradeType()
+GetParseErrorCode()
+GetHeader()
+GetHeaders()
+GetAllHeaders()
+GetAllHeaderNames()
+GetCookie()
+GetAllCookies()
+SetUseCookie()
+IsUseCookie()
+GetStatusCode()
+SendWSMessage()
+GetWSMessageState()
<<create>>-CHttpClientT()
<<destroy>>-CHttpClientT()
ITcpClient
IHttp
+SendChunkData()
+SetLocalVersion()
+GetLocalVersion()
+IsUpgrade()
+IsKeepAlive()
+GetVersion()
+GetContentLength()
+GetContentType()
+GetContentEncoding()
+GetTransferEncoding()
+GetUpgradeType()
+GetParseErrorCode()
+GetStatusCode()
+GetHeader()
+GetHeaders()
+GetAllHeaders()
+GetAllHeaderNames()
+GetCookie()
+GetAllCookies()
+SendWSMessage()
+GetWSMessageState()
<<destroy>>-IHttp()
IHttpRequester
+SendRequest()
+SendLocalFile()
+SendPost()
+SendPut()
+SendPatch()
+SendGet()
+SendDelete()
+SendHead()
+SendTrace()
+SendOptions()
+SendConnect()
+SetUseCookie()
+IsUseCookie()
CHttpClient
<<CppTypedef>>
CHttpsClient
<<CppTypedef>>
IHttpClient
<<CppTypedef>>
IHttpSyncRequester
+OpenUrl()
+CleanupRequestResult()
+SetConnectTimeout()
+SetRequestTimeout()
+GetConnectTimeout()
+GetRequestTimeout()
+GetResponseBody()
IHttpSyncClient
<<CppTypedef>>
CHttpSyncClientT<T>
+Start()
+OpenUrl()
+SendRequest()
+CleanupRequestResult()
+SetConnectTimeout()
+SetRequestTimeout()
+GetConnectTimeout()
+GetRequestTimeout()
+GetResponseBody()
+IsUpgrade()
+IsKeepAlive()
+GetVersion()
+GetContentLength()
+GetContentType()
+GetContentEncoding()
+GetTransferEncoding()
+GetUpgradeType()
+GetParseErrorCode()
+GetHeader()
+GetHeaders()
+GetAllHeaders()
+GetAllHeaderNames()
+GetCookie()
+GetAllCookies()
+AddCookie()
+DeleteCookie()
+DeleteAllCookies()
+GetStatusCode()
+SendWSMessage()
+GetWSMessageState()
<<create>>-CHttpSyncClientT()
<<destroy>>-CHttpSyncClientT()
CHttpSyncClient
<<CppTypedef>>
CHttpsSyncClient
<<CppTypedef>>
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
49
4.1-1 HTTP 组件层次结构
4.1-2 HTTP 组件监听器层次结构
4.2 监听器事件
HTTP IHttpListenerT TCP
IHttpListenerT HTTP 事件可以理解为 TCP 组件监听器 OnReceive 事件的分解。HTTP
件返回值的类型 EnHttpParseResult
ITcpServerListener ITcpAgentListener ITcpClientListener
IHttpListenerT<T>
+OnMessageBegin()
+OnRequestLine()
+OnStatusLine()
+OnHeader()
+OnHeadersComplete()
+OnBody()
+OnChunkHeader()
+OnChunkComplete()
+OnMessageComplete()
+OnUpgrade()
+OnParseError()
<<destroy>>-IHttpListenerT()
IHttpServerListener IHttpAgentListener IHttpClientListener
CHttpServerListener
+OnPrepareListen()
+OnAccept()
+OnHandShake()
+OnReceive()
+OnReceive()
+OnSend()
+OnShutdown()
+OnMessageBegin()
+OnRequestLine()
+OnStatusLine()
+OnHeader()
+OnChunkHeader()
+OnChunkComplete()
+OnUpgrade()
CHttpAgentListener
+OnPrepareConnect()
+OnConnect()
+OnHandShake()
+OnReceive()
+OnReceive()
+OnSend()
+OnShutdown()
+OnMessageBegin()
+OnRequestLine()
+OnStatusLine()
+OnHeader()
+OnChunkHeader()
+OnChunkComplete()
+OnUpgrade()
CHttpClientListener
+OnPrepareConnect()
+OnConnect()
+OnHandShake()
+OnReceive()
+OnReceive()
+OnSend()
+OnMessageBegin()
+OnRequestLine()
+OnStatusLine()
+OnHeader()
+OnChunkHeader()
+OnChunkComplete()
+OnUpgrade()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
50
HPR_OK 解析成功,继续执行
HPR_SKIP_BODY 跳过当前请求 BODY完成本次请求
(仅用于 OnHeadersComplete 件)
HPR_UPGRADE 升级协议,完成本次请求,并且不再进行后续 HTTP 解析
(仅用于 OnHeadersComplete 件)
HPR_ERROR 解析错误,终止解析,断开连接
开始解析事件:
EnHttpParseResult OnMessageBegin(pSender, dwConnID)
pSender -- 事件源对象
dwConnID -- 连接 ID
请求行解析完成事件
(仅用于
HTTP
服务端)
EnHttpParseResult OnRequestLine(pSender, dwConnID, lpszMethod, lpszUrl)
pSender -- 事件源对象
dwConnID -- 连接 ID
lpszMethod -- 请求方法名
lpszUrl -- 请求行中的 URL
状态行解析完成事件
(仅用于
HTTP
客户端)
EnHttpParseResult OnStatusLine(pSender, dwConnID, usStatusCode, lpszDesc)
pSender -- 事件源对象
dwConnID -- 连接 ID
usStatusCode -- HTTP 状态码
lpszDesc -- 状态描述
请求头事件:
EnHttpParseResult OnHeader(pSender, dwConnID, lpszName, lpszValue)
EnHttpParseResult
<<enumeration>>
+HPR_OK
+HPR_SKIP_BODY
+HPR_UPGRADE
+HPR_ERROR
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
51
pSender -- 事件源对象
dwConnID -- 连接 ID
lpszName -- 请求头名称
lpszValue -- 请求头值
请求头完成事件:
EnHttpParseResult OnHeadersComplete(pSender, dwConnID)
pSender -- 事件源对象
dwConnID -- 连接 ID
BODY 报文事件:
EnHttpParseResult OnBody(pSender, dwConnID, pData, iLength)
pSender -- 事件源对象
dwConnID -- 连接 ID
pData -- 数据缓冲区
iLength -- 数据长度
Chunked 报文头事件:
EnHttpParseResult OnChunkHeader(pSender, dwConnID, iLength)
pSender -- 事件源对象
dwConnID -- 连接 ID
iLength -- Chunked 报文体数据长度
Chunked 报文结束事件:
EnHttpParseResult OnChunkComplete(pSender, dwConnID)
pSender -- 事件源对象
dwConnID -- 连接 ID
完成解析事件:
EnHttpParseResult OnMessageComplete(pSender, dwConnID)
pSender -- 事件源对象
dwConnID -- 连接 ID
升级协议事件:
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
52
EnHttpParseResult OnUpgrade(pSender, dwConnID)
pSender -- 事件源对象
dwConnID -- 连接 ID
enUpgradeType -- 协议类型
解析错误事件:
EnHttpParseResult OnParseError(pSender, dwConnID, iErrorCode, lpszErrorDesc)
pSender -- 事件源对象
dwConnID -- 连接 ID
iErrorCode -- 错误代码
lpszErrorDesc -- 错误描述
Web Socket 数据包头事件
EnHandleResult OnWSMessageHeader(pSender, dwConnID, bFinal, iReserved,
iOperationCode, lpszMask, ullBodyLen)
pSender -- 事件源对象
dwConnID -- 连接 ID
bFinal -- 是否结束帧
iReserved -- RSV1/RSV2/RSV3 1
iOperationCode -- 操作码:0x0 - 0xF
lpszMask -- 掩码(nullptr 4 字节掩码,如果为 nullptr 则没有掩码)
ullBodyLen -- 消息体长度
Web Socket 数据包体事件
EnHandleResult OnWSMessageBody(pSender, dwConnID, pData, iLength)
pSender -- 事件源对象
dwConnID -- 连接 ID
pData -- 消息体数据缓冲区
iLength -- 消息体数据长度
Web Socket 数据包完成事件
EnHandleResult OnWSMessageComplete(pSender, dwConnID)
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
53
pSender -- 事件源对象
dwConnID -- 连接 ID
OnHeadersCompleteOnBodyOnMessageComplete OnParseError 是最基本的 4
HTTP 事件,所有应用程序都要对这些事件进行处理其他事件则根据应用程序的实际情况
进行处理。例如: Chunked OnChunkHeader
OnChunkComplete 事件;如果应用程序不会进行协议升级则可忽 OnUpgrade 事件
HP-Socket 支持 Web Socket Http Tunnel 协议升级,协议升级时会触发 OnUpgrade
件,该事件的 enUpgradeType 参数指示升级类型
HUT_WEB_SOCKET Web Socket
HUT_HTTP_TUNNEL HTTP Tunnel
当完成协议升级不再进行 HTTP 解析,也不会触发常规 HTTP 事件如果升级类型为
Web Socket触发 OnWSMessageHeaderOnWSMessageBody OnWSMessageComplete 事件
处理 Web Socket 数据如果升级类型为 HTTP Tunnel后续接收的所有数据都被看作 TCP
数据,触发 OnReceive 事件。
注意:
Sync Client
同步
HTTP
客户端组件
CHttpSyncClient
CHttpsSyncClient
内部会处
理所有事件,因此,它们不需要绑定监听器(构造方法的监听器参数传入
null
;
如果绑定
了监听器则可以跟踪组件的通信过程。
4.3 Cookie 管理
HP-Socket v4.2.x 版本开始 HTTP 客户端组件HttpClientHttpAgent提供进程级
别的 Cookie 管理器,管理器实现了标准 HTTP Cookie 功能,支持 Max-Age
expires
httpOnly
secure 等。
EnHttpUpgradeType
<<enumeration>>
+HUT_NONE
+HUT_WEB_SOCKET
+HUT_HTTP_TUNNEL
+HUT_UNKNOWN
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
54
应用进程
Cookie 管理
客户端组件 客户端组件 客户端组件 客户端组件
HTTP 连接
Cookie 文件
4.3-1 Cookie 管理器
如图 4.3-1 所示,管理器在内存中维护所有 HTTP 客户端组件产生 Cookie可在不同
连接、不同组件对象间共 Cookie,并支持 Cookie 序列化与反序列化。
客户端组件默认设置为使 Cookie,只要客户端组件设置为使 Cookie,它接收到的
Cookie 会自动存入管理器;当发送 HTTP 请求时会自动从管理器中加载 Cookie
如果组件设置为不使用 Cookie(设置方法SetUseCookie(FALSE)它接收到的 Cookie
不会被解析,不会存入管理器;发 HTTP 请求时也不会从管理器中加载 Cookie
注意:管理器内部使用读写锁控制
Cookie
存取,高并发下会带来一些性能损失。如果
确定组件不会用到
Cookie
,可设置为不使用
Cookie
HP-Socket 提供一些管理函数操作管理器,也提 Cookie 辅助函数便于应用程序处
Cookie
从文件加载 Cookie
BOOL HP_HttpCookie_MGR_LoadFromFile(lpszFile, bKeepExists)
lpszFile -- 文件
bKeepExists -- 是否保留管理器中原有的 Cookie
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
55
保存 Cookie 到文件:
BOOL HP_HttpCookie_MGR_SaveToFile(lpszFile, bKeepExists)
lpszFile -- 文件
bKeepExists -- 是否保留文件中原有的 Cookie
清理 Cookie
BOOL HP_HttpCookie_MGR_ClearCookies(lpszDomain, lpszPath)
lpszDomain -- 域,为空则表示所有域
lpszPath -- 路径,为空则表示所有路径
清理过期 Cookie
BOOL HP_HttpCookie_MGR_RemoveExpiredCookies(lpszDomain, lpszPath)
lpszDomain -- 域,为空则表示所有域
lpszPath -- 路径,为空则表示所有路径
设置 Cookie
BOOL HP_HttpCookie_MGR_SetCookie(lpszName, lpszValue, lpszDomain, lpszPath,
iMaxAge, bHttpOnly, bSecure, enSameSite, bOnlyUpdateValueIfExists)
lpszName -- 名称
lpszValue --
lpszDomain --
lpszPath -- 路径
iMaxAge -- 生命周期:> 0 > 存活秒数;= 0 > 立刻删除,< 0 > 到应用程序结束
bHttpOnly -- 是否有 HttpOnly 属性
bSecure -- 是否有 secure 属性
enSameSite -- SameSite 属性:0 > 无;1 –> Strict2 –> LAX
bOnleUpdateValueIfExists -- 如果 Cookie 已存在是否只更新 Cookie
删除 Cookie
BOOL HP_HttpCookie_MGR_DeleteCookie(lpszDomain, lpszPath, lpszName)
lpszDomain --
lpszPath -- 路径
lpszName -- 名称
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
56
设置是否允许第三方 Cookie
void HP_HttpCookie_MGR_SetEnableThirdPartyCookie(bEnableThirdPartyCookie)
bEnableThirdPartyCookie -- TRUE –> 允许;FALSE –> 禁止
检查是否允许第三方 Cookie
BOOL HP_HttpCookie_MGR_IsEnableThirdPartyCookie()
Cookie expires 字符串转换为整数:
BOOL HP_HttpCookie_HLP_ParseExpires(lpszExpires, ptmExpires)
lpszExpires -- expires 字符串
ptmExpires -- expires 整数指针
整数转换为 Cookie expires 字符串:
BOOL HP_HttpCookie_HLP_MakeExpiresStr(lpszBuff, piBuffLen, tmExpires)
lpszBuff -- 字符串缓冲区
piBuffLen -- 缓冲区长度
tmExpires -- expires 整数
生成 Cookie 字符串:
BOOL HP_HttpCookie_HLP_ToString(lpszBuff, piBuffLen, lpszName, lpszValue,
lpszDomain, lpszPath, iMaxAge, bHttpOnly, bSecure, enSameSite)
lpszBuff -- 字符串缓冲区
piBuffLen -- 缓冲区长度
lpszName -- 名称
lpszValue --
lpszDomain --
lpszPath -- 路径
iMaxAge -- 生命周期:> 0 > 存活秒数;= 0 > 立刻删除,< 0 > 到应用程序结束
bHttpOnly -- 是否有 HttpOnly 属性
bSecure -- 是否有 secure 属性
enSameSite -- SameSite 属性:0 > 无;1 –> Strict2 –> LAX
获取当前 UTC 时间:
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
57
__time64_t HP_HttpCookie_HLP_CurrentUTCTime()
Max-Age -> expires
__time64_t HP_HttpCookie_HLP_MaxAgeToExpires(iMaxAge)
iMaxAge -- 生命周期:> 0 > 存活秒数;= 0 > 立刻删除,< 0 > 到应用程序结束
expires -> Max-Age
int HP_HttpCookie_HLP_ExpiresToMaxAge(tmExpires)
tmExpires -- expires 整数
4.4 启动 HTTP 通讯
Http 组件(包括 Https 组件默认情况下在建立连接后会立刻开始 HTTP 通信OnReceive
事件会分解为一系列 HTTP 通信事件)。但在某些场景下需要在启 HTTP 通信前执行一
前置操作,例如:通过 SOCKS 代理服务器与目标服务器通信就是其中一个典型场景。在此
场景中,必须 SOCKS 代理服务器建立连接后才能开 HTTP 通信。
HP-Socket v5.4.3 版本开始,提供了对手工启动 HTTP 通信的支持。调用 HTTP 组件的
SetHttpAutoStart(FALSE) 方法把组件设置为手工启动 HTTP 通信模式,在执行完前置操作后
调用 StartHttp() 启动 HTTP 通信。
手工启动 HTTP 通信:
BOOL StartHttp(dwConnID)
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
58
5 UDP ARQ
HP-Socket v5.5.x 版本开始,提供 UDP ARQ(自动重传请求 UDP可靠 UDP)组件:
IUdpArqServer IUdpArqClient在低带宽、高延时或丢包严重的网络环境中,可以提供比
TCP 更高效的网络传输性能。
5.1 组件接口
UDP ARQ 组件 IUdpArqServer / IUdpArqClient 的操作方法和监听器接口与常规 UDP
IUdpServer / IUdpClient 一致,只在常规 UDP 组件的基础上增加了若干 ARQ 通信相
的参数设置、获取方法。
Name
Component Intface
Listener Intface
Implement Class
Role
Base Class
UDP Server
IUdpServer
IUdpServerListener
CUdpServer
Server
UDP Client
IUdpClient
IUdpClientListener
CUdpClient
Client
UDP Cast
IUdpCast
IUdpCastListener
CUdpCast
Client
UDP ARQ Server
IUdpArqServer
IUdpServerListener
CUdpArqServer
Server
CUdpServer
UDP ARQ Client
IUdpArqClient
IUdpClientListener
CUdpArqClient
Client
CUdpClient
5.1-1 UDP 件分类
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
59
5.1-1 UDP 组件层次结构
5.2 握手协议
HP-Socket 使用 KCP 实现 ARQ 通信,但通信协商方式与常规 KCP 不同,常规 KCP
要通信双方使用相同的会 IDHP-Socket 使用自身的通信握手协议实现通信协商。通信双
方可以使用各自独立的会 ID
如图 5.2-1 HP-Socket ARQ
IUdpArqServer 组件接收 OnAccept 事件或 IUdpArqClient 件接收到 OnConnect 事件时
即开始 ARQ 握手,握手方式为定时向对方发送握手报文并处理对方发过来的握手报文,
至握手完成或超时终止。握手完成会接收 OnHandshake 件;握手超时会接收到 OnClose
事件,错误代码 ERROR_TIMEOUT
协商报文格式:
MM C F XXXX YYYY
报文长度 12 字节
IUdpClient
+SetMaxDatagramSize()
+GetMaxDatagramSize()
+SetDetectAttempts()
+SetDetectInterval()
+GetDetectAttempts()
+GetDetectInterval()
CUdpClient
CUdpArqClient
IArqClient
+SetNoDelay()
+SetTurnoffCongestCtrl()
+SetFlushInterval()
+SetResendByAcks()
+SetSendWndSize()
+SetRecvWndSize()
+SetMinRto()
+SetMaxTransUnit()
+SetMaxMessageSize()
+SetHandShakeTimeout()
+GetNoDelay()
+GetTurnoffCongestCtrl()
+GetFlushInterval()
+GetResendByAcks()
+GetSendWndSize()
+GetRecvWndSize()
+GetMinRto()
+GetMaxTransUnit()
+GetMaxMessageSize()
+GetHandShakeTimeout()
+GetWaitingSendMessageCount()
<<destroy>>+IArqClient()
IUdpArqClient
IClient
+Start()
+Stop()
+Send()
+SendPackets()
+PauseReceive()
+IsPauseReceive()
+IsSecure()
+IsConnected()
+SetExtra()
+GetExtra()
+HasStarted()
+GetState()
+GetLastError()
+GetLastErrorDesc()
+GetConnectionID()
+GetLocalAddress()
+GetRemoteHost()
+GetFreeBufferPoolSize()
+GetPendingDataLength()
+SetFreeBufferPoolSize()
+SetFreeBufferPoolHold()
+GetFreeBufferPoolHold()
<<destroy>>-IClient()
IServer
+Start()
+GetListenAddress()
IUdpArqServer
IArqSocket
+SetNoDelay()
+SetTurnoffCongestCtrl()
+SetFlushInterval()
+SetResendByAcks()
+SetSendWndSize()
+SetRecvWndSize()
+SetMinRto()
+SetMaxTransUnit()
+SetMaxMessageSize()
+SetHandShakeTimeout()
+GetNoDelay()
+GetTurnoffCongestCtrl()
+GetFlushInterval()
+GetResendByAcks()
+GetSendWndSize()
+GetRecvWndSize()
+GetMinRto()
+GetMaxTransUnit()
+GetMaxMessageSize()
+GetHandShakeTimeout()
+GetWaitingSendMessageCount()
<<destroy>>+IArqSocket()
CUdpServer
IUdpServer
+SetMaxDatagramSize()
+GetMaxDatagramSize()
+SetPostReceiveCount()
+GetPostReceiveCount()
+SetDetectAttempts()
+SetDetectInterval()
+GetDetectAttempts()
+GetDetectInterval()
CUdpArqServer
IComplexSocket
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
60
1-2 字节 :固定魔数 0xBB4F
3 字节 :命令类型,目前只使用了握手命令 0x01
4 字节 :命令标识,0x00 - 未完成,0x01 - 已完成
5-8 字节 :本方会话 ID
9-12 字节 :对方会话 ID,如未收到对方会话 ID 则用 0x00000000 填充
注意:
IUdpArqServer
通过客户端“
IP
地址
+
端口
+
会话
ID
”标识一个远程连接,
在客户端断开又重连的情形下,服务端可能未收到前一个连接的断开通知。因此客户端需要
确保前后两个连接的
IP
地址
+
端口
+
会话
ID
不会完全相同。最简单的做法是让前后
两个连接使用不同的会话
ID
5.2-1 ARQ 通信过程
5.3 配置参数
SetNoDelay(BOOL)
是否开启
nodelay
模式(默认:
FALSE
,不开启)
SetTurnoffCongestCtrl(BOOL)
是否关闭拥塞控制(默认:
FALSE
,不关闭)
SetFlushInterval(DWORD)
数据刷新间隔(毫秒,默认:
60
Handshake
Server ApplicationServer ComponentClient Application Client Component
Start()
OnPrepareListen
Start()
OnPrepareConnect
Connect
OnAccept
OnConnect
Handshake Negotiation
Handshake Negotiation
OnHandShake OnHandShake
Send()
Send ARQ Message
OnReceive
OnSend
Send()
OnReceive
Send ARQ Message
OnSend
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
61
SetResendByAcks(DWORD)
快速重传
ACK
跨越次数(默认:
0
,关闭快速重传)
SetSendWndSize(DWORD)
发送窗口大小(数据包数量,默认:
128
SetRecvWndSize(DWORD)
接收窗口大小(数据包数量,默认:
512
SetMinRto(DWORD)
最小重传超时时间(毫秒,默认:
30
SetMaxTransUnit(DWORD)
最大传输单元(默认:
0
,与
UDP
参数
SetMaxDatagramSize(DWORD)
一致)
SetMaxMessageSize(DWORD)
最大数据包大小(默认:
4096
SetHandShakeTimeout(DWORD)
握手超时时间(毫秒,默认:
5000
SetMaxMessageSize(DWORD) SetHandShakeTimeout(DWORD)外,其他配置参数
均与 KCP 相关,请参考 KCP 对相关参数的说明。
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
62
6 线程池
6.1 组件接口
HP-Socket v5.4.x 版本开始,提供线程池组件 IHPThreadPool协助用户实现通信逻辑与
业务逻辑分离,提高应用程序的整体执行效率IHPThreadPool 提供以下主要操作方法。
些方法成功返 TRUE失败返回 FALSE失败可通 SYS_GetLastError() 取系统错误
码。
6.1-1 Thread Pool 组件接口
启动线程池
BOOL Start(dwThreadCount = 0, dwMaxQueueSize = 0, enRejectedPolicy =
TRP_CALL_FAIL, dwStackSize = 0)
dwThreadCount 线程数量,(默认:0
>0 dwThreadCount
=0 (CPU 核数 * 2 + 2)
<0 (CPU 核数 * (-dwThreadCount))
dwMaxQueueSize 任务队列最大容量(默认:0不限制)
enRejectedPolicy 任务拒绝处理策略
TRP_CALL_FAIL (默认)立刻返回失败
TRP_WAIT_FOR :等待(直到成功、超时或线程池关闭等原因导致失败)
TRP_CALLER_RUN :调用者线程直接执行
dwStackSize 线程堆栈空间大小(默认:0 -> 操作系统默认)
关闭线程池
在规定时间内关闭线程池组件,如果工作线程在最大等待时间内未能正常关闭,会尝试
强制关闭,这种情况下很可能会造成系统资源泄漏。
IHPThreadPool
+Start()
+Stop()
+Wait()
+Submit()
+Submit()
+AdjustThreadCount()
+HasStarted()
+GetState()
+GetQueueSize()
+GetTaskCount()
+GetThreadCount()
+GetMaxQueueSize()
+GetRejectedPolicy()
<<destroy>>+IHPThreadPool()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
63
BOOL Stop(dwMaxWait = INFINITE)
dwMaxWait 最大等待时间(毫秒,默认INFINITE,一直等待)
提交任务
BOOL Submit(fnTaskProc, pvArg, dwMaxWait = INFINITE)
fnTaskProc 任务处理函数
pvArg 务参数
dwMaxWait 任务提交最大等待时间(毫秒,仅对 TRP_WAIT_FOR 类型线程
池生效,默认:INFINITE,一直等待
** SYS_GetLastError() 错误码 ERROR_DESTINATION_ELEMENT_FULL 表示
任务队列已满。
提交 Socket 任务
BOOL Submit(pTask, dwMaxWait = INFINITE)
pTask 任务参数
dwMaxWait 任务提交最大等待时间(毫秒,仅对 TRP_WAIT_FOR 类型线程
池生效,默认:INFINITE,一直等待
** SYS_GetLastError() 错误码 ERROR_DESTINATION_ELEMENT_FULL 表示
任务队列已满。
注意:
pTask
HP_Create_SocketTaskObj( )
函数创建,当
Submit(pTask)
提交成功
线
pTask
对象;
HP_Destroy_SocketTaskObj( )
销毁
pTask
对象。
动态调整线程池大小
BOOL AdjustThreadCount(dwNewThreadCount)
dwNewThreadCount 线程数量
>0 dwNewThreadCount
=0 (CPU 核数 * 2 + 2)
<0 (CPU 核数 * (-dwNewThreadCount))
6.2 监听器事件
HP-Socket v5.8.5 版本开始提供了线程池监听器接口 IHPThreadPoolListener线程池
件可以绑定监听器处理以下生命周期事件:
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
64
线程池启动事件
void OnStartup(pThreadPool)
pThreadPool -- 事件源对象
线程池关闭事件
void OnShutdown(pThreadPool)
pThreadPool -- 事件源对象
工作线程启动事件
(每个工作线程触发一次)
void OnWorkerThreadStart(pThreadPool, dwThreadID)
pThreadPool -- 事件源对象
dwThreadID -- 工作线程 ID
工作线程退出事件
(每个工作线程触发一次)
void OnWorkerThreadEnd(pThreadPool, dwThreadID)
pThreadPool -- 事件源对象
dwThreadID -- 工作线程 ID
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
65
7 压缩 / 解压缩
7.1 组件接口
HP-Socket 以前版本提供了单次压缩/解压相关辅助函数,所谓“单次”是指传递进压缩
/解压函数的输入数据必须是完整数据,不能是数据片段。压缩/压函数对输入数据进行
次性压缩/解压。因此单次压缩/压函数能只能处理少量输入数据:
int SYS_Compress() ZLib 压缩
int SYS_CompressEx() ZLib 级压缩
int SYS_Uncompress() ZLib 解压
int SYS_UncompressEx() :高级 ZLib 解压
int SYS_GuessCompressBound() 推测 ZLib 压缩结果长
int SYS_GZipCompress() GZip 压缩
int SYS_GZipUncompress() GZip 解压
int SYS_GZipGuessUncompressBound() 推测 Gzip 解压结果长度
int SYS_BrotliCompress() Brotli 压缩
int SYS_BrotliCompressEx() Brotli 高级压缩
int SYS_BrotliUncompress() Brotli 解压
int SYS_BrotliGuessCompressBound() 推测 Brotli 压缩结果长度
HP-Socket v5.8.6 本开始,提供流式数据压缩/解压接口,能处理大量输入数据或总
不确定的流式数据。
7.1.1 压缩器组件接口
7.1.1-1 压缩器组件接口
处理输入数据
BOOL Process(pData, iLength, bLast, pContext = nullptr)
pData 待压缩数据缓冲
iLength 待压缩数据长度
IHPCompressor
+Process()
+IsValid()
+Reset()
<<destroy>>+IHPCompressor()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
66
bLast 标识:是否最后一段数据
pContext 上下文参数:传递给回调函数 Fn_CompressDataCallback
应用程序可循环调用该方法,用以压缩流式或分段数据执行成返回 TRUE失败返
FALSE,失败时可通过 SYS_GetLastError() 获取错误码。
重置压缩器
BOOL Reset()
开始处理一个新数据流前必须重置压缩器。
(注:应用程序通常不需要显式调用该方法因为
Process()
方法在完成处理或中断处
一个数据流后会自动重置压缩器)
检测压缩器是否可用
BOOL IsValid()
7.1.2 解压器组件接口
7.1.2-1 解压器组件接
处理输入数据
BOOL Process(pData, iLength, bLast, pContext = nullptr)
pDat 待解压数据缓冲区
iLength 待解压数据长度
pContext 上下文参数:传递给回调函数 Fn_DecompressDataCallback
应用程序可循环调用该方法,用以解压流式或分段数据执行成返回 TRUE失败返
FALSE,失败时可通过 SYS_GetLastError() 获取错误码。
重置解压器
BOOL Reset()
IHPDecompressor
+Process()
+IsValid()
+Reset()
<<destroy>>+IHPDecompressor()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
67
开始处理一个新数据流前必须重置解压器。
(注:应用程序通常不需要显式调用该方法因为
Process()
方法在完成处理或中断处
一个数据流后会自动重置解压器)
检测解压器是否可用
BOOL IsValid()
7.1.3 输出数据回调
输出数据回调函数
typedef BOOL (*Fn_DataCallback)(pData, iLength, bLast, pContext);
typedef Fn_DataCallback Fn_CompressDataCallback;
typedef Fn_DataCallback Fn_DecompressDataCallback;
pData 待解压数据缓冲区
iLength 解压数据长度
pContext 上下文参数: Process() 方法带人
在压缩/解压器的 Process(pData, iLength, [bLast,] pContext) 方法执行过程中,当产生
出时会以输出数据和 pContext 为入参调用“输出数据回调函数”该回调函数在创建压缩/
压器对象时指定(参考:对象创建)。
回调函数返回 TRUE 继续处理;返回 FALSE 则中断处理,Process() 返回 FALS
SYS_GetLastError() 返回 ERROR_CANCELLED 错误码
7.2 对象创建
目前支持 ZLib/GZip Brotli 压缩算法:
创建 ZLib 压缩器对象
IHPCompressor* HP_Create_ZLibCompressor(fnCallback, iWindowBits, iLevel, iMethod,
iMemLevel, iStrategy)
fnCallback 输出数据回调函数
参数默认值
iWindowBits = 15, iLevel = -1, iMethod = 8, iMemLevel = 8, iStrategy = 0
创建 GZip 压缩器对象
IHPCompressor* HP_Create_GZipCompressor(fnCallback, iLevel, iMethod, iMemLevel,
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
68
iStrategy)
fnCallback 输出数据回调函数
参数默认值
iLevel = -1, iMethod = 8, iMemLevel = 8, iStrategy = 0
创建 Brotil 压缩器对象
IHPCompressor* HP_Create_BrotilCompressor(fnCallback, iQuality, iWindow, iMode)
fnCallback 输出数据回调函数
参数默认值
iQuality = 11, iWindow = 22, iMode = 0
创建 ZLib 解压器对象
IHPDecompressor* HP_Create_ZLibDecompressor(fnCallback, iWindowBits)
fnCallback 输出数据回调函数
参数默认值
iWindowBits = 15
创建 GZip 解压器对象
IHPDecompressor* HP_Create_GZipDecompressor(fnCallback)
fnCallback 输出数据回调函数
创建 Brotil 解压器对象
IHPDecompressor* HP_Create_BrotliDecompressor(fnCallback)
fnCallback 输出数据回调函数
销毁压缩器对象
void HP_Destroy_Compressor(pCompressor)
pCompressor 压缩器对象指针
销毁解压器对象
void HP_Destroy_Decompressor(pDecompressor)
pDecompressor 解压器对象指针
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
69
8 Linux
HP-Socket for Linux 提供的 API 接口 Windows 版本一致,但实现代码则完全独立
HP-Socket for Linux 使用了 C++14 标准的新特性,需要 GCC 6.x 以上版本的编译器进行编
译。
注意:
HP-Socket for Linux
编译运行要求:
1) Linux
内核版本:
2.6.32
及以上
2) GCC
版本:
6.x
及以上
3) glibc
版本:
2.14.x
及以上
4)
依赖库:
librt
libdl
libpthread
8.1 编译
HP-Socket 发布包已提供 x86 x64 平台下的编译好的二进制库文件示例 Demo 可执
行文件(
编译环境:
Linux 2.6.32
GCC 6.3.1。也可以通过以下方式自行编译
1 Windows
远程编译:
HP-Socket 发行包中提供了 HP-Socket 及其示例 Demo
Visual Studio 项目工程,可以打开对应项目工程编译 HP-Socket 库或示例 Demo
script/ ms-build-libs.batms-build-demos.batms-build-
all.bat 分别编译 HP-Socket 库或(和)示例 Demo
2 compile.sh可以使用 HP-Socket 发行包中提供的 script/compile.sh 编译脚本编
HP-Socket 库文件。注:compile.sh 只编译 HP-Socket 库,不编译示例 Demo
8.1-1 compile.sh 编译脚本
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
70
8.2 安装
发布包提供的 script/install.sh 脚本用于安装(或卸载)HP-Socket,它会安装(或卸载
当前平台的库文件进行。install.sh 脚本支持以下参数
8.2-1 install.sh 安装脚本
注意:
compile.sh
编译脚本依赖发行包的
script/
src/
include/
dependent/
目录;
install.sh
安装脚本依赖发行包的
script/
include/
lib/
目录,如果要安装示例
Demo
的执行文件,还
需要依赖
demo/Release/
目录。
8.3 Android NDK
HP-Socket 提供了 Android NDK 库文件构建脚本 script/build-android-ndk.shWindows
台:
build-android-ndk.bat,装配置好 NDK 后执行 build-android-ndk.sh 进行库文件构建
构建脚本默认会构建当前 NDK 支持的所有 ABI 的动态库和静态库,并把构建目标库文件输
出到 lib/android-ndk/ 目录。如有特殊需要请为构建脚本提供相应的命令行参数。
(执行默认构建)
8.3.1 ABIs
构建脚本默认会构建当 NDK 支持的所有非过 ABI 的库文件,你可以为构建脚本提
APP_ABI 令行参数构建特定 ABI 的库文件。
(只构建
armeabi-v7a
x86 ABI
库文件)
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
71
8.3.2 功能特性开关
构建脚本默认会构建所有功能特性(UDP / SSL / HTTP / ZLIB / BROTLI / ICONV,你可
以为构建脚本提 __XXX_DISABLED=true 参数来移除某些功能特性。
_UDP_DISABLED=true :移除 UDP
_SSL_DISABLED=true :移除 SSL
_HTTP_DISABLED=true :移除 HTTP
_ZLIB_DISABLED=true :移除 ZLIB
_BROTLI_DISABLED=true :移除 BROTLI
_ICONV_DISABLED=true :移除 ICONV
_MIMALLOC_DISABLED=true :禁用 mimalloc 内存分配器
(移除
SSL
ICONV
注意:如果在构建库时移除了某些功能特性,那么在编译使用该库的应用程序时需要定
移除了
SSL
ICONV
需要定义
_SSL_DISABLED
_ICONV_DISABLED
宏。
8.3.3 其他选项
构建脚本 build-android-ndk.sh 只是 Android NDK 命令 ndk-build 简单包装,构建
本支持 ndk-build 的所有命令行参数。ndk-build 的详细说明请参官方文
以下示例演示如下构建选项:
构建 armeabi-v7a x86_64 ABI 库文件
移除 UDPZLIB ICONV 功能特性
库文件输出到 lib/android-ndk/ 目录
obj 中间文件输出 lib/android-ndk/obj 目录
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
72
9 使用方式
HP-Socket 支持 MBCS Unicode 字符集支持 32 位和 64 位应用程序可以通过源代
码、DLL LIB 方式使用 HP-SocketHP-Socket 发行包中已经提供了 HPSocket DLL
HPSocket4C DLL
注意:
HP-Socket v5.2.x
开始,发行包不再分别提供
SSL
和非
SSL
库文件,发行包中提
SSL
HTTP
组件,如果去除
SSL
HTTP
_SSL_DISABLED
_HTTP_DISABLED
宏重新编译。
9.1 源代码
HP-Socket 依赖于 Src/Common/ 目录下的一些公共代码。所以,通过源代码方式使用 HP-
Socket 时需要把 HP-Socket Src/ 目录和 Src/Common/ 目录下的相应代码文件加入到工程
项目(参考:TestEcho / TestEcho-UDP 示例 Demo)。
9.2 静态库
HP-Socket 发行包中 Windows 版本的 Project/HPSocketLIB Project/HPSocketLIB4C
程项目用于编 HPSocket LIB HPSocket4C LIB输出目录为 Lib/x86(x64)/static/如果需
要可以自己编译。静态库与动态库的使用方式一致,请参考后续章节。
(静态库引用方式参考:TestEcho-SSL-4C / TestEcho-SSL-PFM 示例 Demo)。
注意:Windows 平台下,如果工程项目使用 HPSocket LIB HPSocket4C LIB,需要在
工程属性中定义预处理宏 -> HPSOCKET_STATIC_LIB
9.3 HPSocket DLL
HPSocket DLL 导出 C++ 编程接口,是 C++ 程序使用 HP-Socket 的首选方式HPSocket
DLL 通过 HP-Socket 发行包中的 Project/HPSocketDLL 工程项目编译生成,输出以下 DLL
Lib\x86\HPSocket.dll 32 /MBCS/Release
Lib\x86\HPSocket_D.dll 32 /MBCS/Debug
Lib\x86\HPSocket_U.dll 32 /Unicode/Release
Lib\x86\HPSocket_UD.dll 32 /Unicode/Debug
Lib\x64\HPSocket.dll 64 /MBCS/Release
Lib\x64\HPSocket_D.dll 64 /MBCS/Debug
Lib\x64\HPSocket_U.dll 64 /Unicode/Release
Lib\x64\HPSocket_UD.dll 64 /Unicode/Debug
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
73
使用 HPSocket DLL 需 要 include/hpsocket/SocketInterface.h
include/hpsocket/HPSocket.h 以及 DLL *.lib
include/hpsocket/HPSocket.h 除了导出组件的创建、销毁方法和组件接口外,还定义了各组件
的智能指针(如:CTcpServerPtr / CTcpClientPtr通过这些智能指针可以更方便地使 HP-
Socket 组件。(参考:TestEcho-Pull / TestEcho-PFM 示例 Demo)。
HPSocket DLL 包含 SSL SSL SSL
include/hpsocket/HPSocket-SSL.hinclude/hpsocket/SocketInterface.h 以及 DLL 对应的*.lib
件加入到工程项目。(参考TestEcho-SSL-Pack 示例 Demo)。
通过 DLL 方式使用 HP-Socket,当需要更新或升级 HP-Socket 时,如果 DLL 接口发生
变化则必须重新编译应用程序;如果 DLL 接口没有改变则直接替换 DLL 即可,不需要重新
编译应用程序。
9.4 HPSocket4C DLL
HPSocket4C DLL 导出 C 编程接口,提供给 C 语言或其它编程语言使用 HP-Socket
HPSocket4C DLL 通过 HP-Socket 发行包中的 Project/HPSocketDLL4C 工程项目编译生成,
输出以下 DLL
Lib\x86\HPSocket4C.dll 32 /MBCS/Release
Lib\x86\HPSocket4C_D.dll 32 /MBCS/Debug
Lib\x86\HPSocket4C_U.dll 32 /Unicode/Release
Lib\x86\HPSocket4C_UD.dll 32 /Unicode/Debug
Lib\x64\HPSocket4C.dll 64 /MBCS/Release
Lib\x64\HPSocket4C_D.dll 64 /MBCS/Debug
Lib\x64\HPSocket4C_U.dll 64 /Unicode/Release
Lib\x64\HPSocket4C_UD.dll 64 /Unicode/Debug
使用 HPSocket4C DLL 时需要 include/hpsocket/HPSocket4C.h 以及 DLL 对应的*.lib
件加入到工程项目。(参考:TestEcho-4C 示例 Demo)。
HPSocket4C DLL 包含 SSL 件和 SSL 件,如果需用到 SSL 组件则需要
include/hpsocket/HPSocket4C-SSL.h 以及 DLL 对应的*.lib 件加程项
TestEcho-SSL-Pack 示例 Demo)。
通过 4C DLL 方式使用 HP-Socket当需要更新或升级 HP-Socket 如果 DLL 接口发
生变化则必须重新编译应用程序;如果 DLL 接口没有改变则直接替 DLL 可,不需要重
新编译应用程序
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
74
9.5 扩展支持
HP-Socket 发行包提供了易语言模块和支持 SDK;对于没有提供 SDK 的编程语言可
以通过 HPSocket4C DLL 提供的 C 编程接口使用 HP-Socket
开源项目 HPSocket.net 提供 HP-Socket .NetCore SDK
开源项目 HPSocket for macOS 提供 HP-Socket Mac OSX 平台移植版本。
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
75
10
10.1 示例 Demo
10.1.1 Windows 示例
项目名称
使用组件
引用方式
HttpProxy
(Server-1)
TCP Server
TCP Agent
DLL
HTTP 代理服务器(TCP
现)
HttpProxy
(Server-2)
HTTP Server
TCP Agent
DLL
HTTP 代理服务器(HTTP
现)
TestEcho
TCP Server
TCP Client
SRC
Echo 服务端和客户端
TestEcho-4C
TCP PULL Server
TCP PULL Client
4C DLL
Echo 服务端和客户端
TestEcho-Agent
(Agent-4C)
TCP PULL Agent
4C DLL
Echo 客户端
TestEcho-Agent
(Agent-PFM)
TCP Agent
SRC
Echo 性能测试客户端
TestEcho-Agent
(Agent-PULL)
TCP PULL Agent
DLL
Echo 客户端
TestEcho-PFM
TCP Server
TCP Client
DLL
Echo 性能测试服务端和客户端
TestEcho-Pull
TCP PULL Server
TCP PULL Client
DLL
Echo 服务端和客户端
TestEcho-Pack
TCP PACK Server
TCP PACK Client
4C DLL
DLL
Echo 服务端和客户端
TestEcho-UDP
UDP Server
UDP Client
SRC
Echo 服务端和客户端
TestEcho-UDP-PFM
UDP Server
UDP Client
DLL
Echo 性能测试服务端和客户端
TestUDPCast
UDP Cast
SRC
组播(广播)网络成员
TestUDPNode
UDP Node
SRC
UDP 节点
TestEcho-SSL
SSL Server
SSL Client
SRC
Echo 服务端和客户端
TestEcho-SSL-4C
SSL PULL Server
SSL PULL Client
4C LIB
Echo 服务端和客户端
TestEcho-SSL-Pack
SSL PACK Server
SSL PACK Client
4C DLL
DLL
Echo 服务端和客户端
TestEcho-SSL-PFM
SSL Server
LIB
Echo 性能测试服务端和客户端
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
76
SSL Agent
TestEcho-Http
HTTP Server
HTTP Client
HTTP Sync Client
SRC
Echo 服务端和客户端
TestEcho-Http-4C
HTTP Server
HTTP Client
HTTP Sync Client
4C LIB
4C DLL
4C DLL
Echo 服务端和客户端
TestEcho-ARQ
UDP ARQ Server
UDP ARQ Client
SRC
Echo 服务端和客户端
TestEcho-ARQ-PFM
UDP ARQ Server
UDP ARQ Client
DLL
Echo 性能测试服务端和客户端
10.1.1-1 Windows 示例
10.1.2 Linux 示例
项目名称
使用组件
引用方式
testecho
TCP Server
TCP Agent
TCP Client
SRC
Echo 服务端和客户端
testecho-pfm
TCP Server
TCP Agent
TCP Client
SRC
Echo 性能测试服务端和客户端
testecho-pull
TCP PULL Server
TCP PULL Agent
TCP PULL Client
SRC
Echo 服务端和客户端
testecho-pack
TCP PACK Server
TCP PACK Agent
TCP PACK Client
SRC
Echo 服务端和客户端
testecho-udp
UDP Server
UDP Client
UDP Cast
UDP Node
SRC
Echo 服务端
Echo 客户端
组播(广播)网络成员
UDP 节点
testecho-udp-pfm
UDP Server
UDP Client
SRC
Echo 性能测试服务端和客户端
testecho-lib
TCP PULL Server
TCP PULL Agent
TCP PULL Client
SO
4C SO
4C SO
Echo 服务端和客户端
testecho-ssl
SSL Server
SSL Agent
SSL Client
SRC
Echo 服务端和客户端
testecho-ssl-pfm
SSL Server
SSL Agent
SO
Echo 性能测试服务端和客户端
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
77
SSL Client
testecho-ssl-pull
SSL PULL Server
SSL PULL Agent
SSL PULL Client
SO
Echo 服务端和客户端
testecho-ssl-pack
SSL PACK Server
SSL PACK Agent
SSL PACK Client
4C SO
Echo 服务端和客户端
Testecho-http
HTTP Server
HTTP Agent
HTTP Client
HTTP Sync Client
SRC
Echo 服务端和客户端
Testecho-http-4c
HTTP Server
HTTP Agent
HTTP Client
HTTP Sync Client
4C SO
Echo 服务端和客户端
testecho-arq
UDP ARQ Server
UDP ARQ Client
SRC
Echo 服务端和客户端
testecho-arq-pfm
UDP ARQ Server
UDP ARQ Client
A
Echo 性能测试服务端和客户端
10.1.2-1 Linux 示例
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
78
10.2 辅助函数
LPCTSTR HP_GetSocketErrorDesc() :获取 HPSocket 误码对应描述
DWORD SYS_GetLastError() :封装 API 函数 GetLastError() / errno
LPCSTR SYS_GetLastErrorStr() [L ] :封装 API 函数 strerror()
int SYS_WSAGetLastError() [W] :封装 API 函数 WSAGetLastError()
int SYS_SetSocketOption() :封装 API 函数 setsockopt()
int SYS_GetSocketOption() :封装 API 函数 getsockopt()
int SYS_IoctlSocket() :封装 API 函数 ioctlsocket()
int SYS_WSAIoctl() [W] :封装 API 函数 WSAIoctl()
int SYS_fcntl_SETFL() [L ] :封装 API 函数 fcntl()
设置 F_SETFL
int SYS_SSO_ Block() [L ] :设置 FD 选项:O_NONBLOCK
int SYS_SSO_NoDelay() 设置 socket 选项:TCP_NODELAY
int SYS_SSO_DontLinger() 设置 socket 选项:SO_DONTLINGER
int SYS_SSO_Linger() 设置 socket 选项:SO_LINGER
int SYS_SSO_RecvBuffSize() 设置 socket 选项SO_RCVBUF
int SYS_SSO_SendBuffSize() 设置 socket 选项:SO_SNDBUF
int SYS_SSO_RecvTimeout() 设置 socket 选项:SO_RCVTIMEO
int SYS_SSO_SendTimeout() 设置 socket 选项:SO_SNDTIMEO
int SYS_SSO_ReuseAddress() 设置 socket 地址重用策略
BOOL SYS_GetSocketLocalAddress() 获取 socket 本地地址
BOOL SYS_GetSocketRemoteAddress() 获取 socket 远程地址
ULONG SYS_EnumHostIPAddresses() :枚举主 IP 地址
BOOL SYS_FreeHostIPAddresses() :释放主机 IP 地址结构体
BOOL SYS_IsIPAddress() :检查字符串是否符合 IP 地址格式
BOOL SYS_GetIPAddress() :通过主机名获取 IP 地址
BOOL SYS_NToH64() 64 位网络字节序转主机字节序
BOOL SYS_HToN64() 64 位主机字节序转网络字节序
BOOL SYS_SwapEndian16() :短整型高低字节交
BOOL SYS_SwapEndian32() :长整型高低字节交
BOOL SYS_IsLittleEndian() :检查是否小端字节序
BOOL SYS_CodePageToUnicode() [W] CP_XXX -> UNICODE
BOOL SYS_UnicodeToCodePage() [W] UNICODE -> CP_XXX
BOOL SYS_CharsetConvert() [L ] Charset-A -> Charset-B
BOOL SYS_GbkToUnicode() GBK -> UNICODE
BOOL SYS_UnicodeToGbk() UNICODE -> GBK
BOOL SYS_Utf8ToUnicode() UTF8 -> UNICODE
BOOL SYS_UnicodeToUtf8() UNICODE -> UTF8
BOOL SYS_GbkToUtf8() GBK -> UTF8
BOOL SYS_Utf8ToGbk() UTF8 -> GBK
int SYS_GuessBase64EncodeBound() 计算 Base64 编码后长度
int SYS_GuessBase64DecodeBound() 计算 Base64 解码后长度
int SYS_Base64Encode() Base64 编码
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
79
int SYS_Base64Decode() Base64 解码
int SYS_GuessUrlEncodeBound() 计算 URL 编码后长度
int SYS_GuessUrlDecodeBound() 计算 URL 解码后长度
int SYS_UrlEncode() URL 编码
int SYS_UrlDecode() URL 解码
LPBYTE SYS_Malloc() :分配内存
LPBYTE SYS_Realloc() :重新分配内存
VOID SYS_Free() :释放内存
LPVOID SYS_Calloc() :分配内存块
LPBYTE SYS_Alloca() 分配栈内存
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
80
10.3 FAQ
Q-01
Connection ID 的生成规则是什么?数值溢出怎么办?
A
Connection ID 32 位程序中是 4 字节,在 64 位程序中是 8 字节Client 组件
Agent/Server 组件有不同的生成规则:
1) Agent/Server 组件:Connection ID 取值范围:1 - N*256其中 N 为最大连
接数。HPSocket 通过内部算法合理分配一个安全随机的 Connection ID
2) Client 组件:当 Connection ID 溢出时会重新从 1 开始递增。理论上 32
位程序中存在 Connection ID 重复的可能,但不必担心,因为这种情况只
出现在一种不可能发生的场景:
客户端进程同时启动多
Client
组件,
且“创建了
40
亿次连接后第一个启动
Client
组件还没断开”
Q-02
可以在事件处理函数中调用 Start() / Stop() 吗?
A
不可以。由于监听器事件(OnReceive / OnClose 等)通常都在通信线程中被触
发,Stop() 方法需要等待通信线程结束,这样会导致自己等等自己结束的死循环,
因此不能在监听器事件处理代码中调 Start() / Stop() 控制方法。
Q-03
关闭 Server Agent 时,一直卡在 Stop()方法里面,Why
A
几种可能:
1) 在事件处理函数中调 Stop() 方法(参考:Q-02)。
2) 一个或多个通信线程都被死锁了,导致 Stop() 方法一直等不到所有通信
线程结束。如果是所有通信线程都被死锁还会伴随另一种现象:组件不能
接收和处理任何通信请求
3) 在自定义 Windows DLL 使用 HP-Socket Server 组件,但在卸载该 DLL
之前没有手工关闭该 Server 组件,导致 Server 组件在自动析构时卡在 Stop()
方法中。解决方法:卸 DLL 之前显式关闭 HP-Socket Server 组件。
4) 如果有些机器能顺利执行 Stop() 方法有些机器不能,可能是 Winsock
破坏了。解决身份netsh
winsock reset重启机器。
Q-04
可以在事件处理函数中更新用户界面吗
A
不可以。事件处理函数由 Socket IO 线程触发,如果在事件处理函数中更新用户
界面会急剧降低应用程序性能并且很容易造成死锁应该使用其他方法异步更新用
户界面。
Q-05
如何断开超长连接?
A
所谓超长连接是指连接时长超过正常时长的连接Server Agent 组件提
DisconnectLongConnections() 方法断开所有超长连接,也提供 GetConnectPeriod()
方法用来获取某个连接的时长。
Q-06
如何断开静默连接?
A
Server Agent
DisconnectSilenceConnections() 方法断开所有静默连接,也提供 GetSilencePeriod()
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
81
方法用来获取某个连接的静默时间注意:当组件开启了静默标记时上述两个方法
才有效,可在组件启动前调用SetMarkSilence(TRUE)方法来开启静默标记。HP-
Socket v3.5.x 及后续版本默认开启静默标记。
Q-07
断线重连该如何实现?
A
Agent 组件可以在接收到断线通知事件OnClose时立刻发 Connect() 调用
进行重连;Client 组件则不能接收到断线通知事OnClose时立刻调用 Start()
法进行重连。因此Client 组件可以选择以下方法实现重连:
1) 启动一个监测线程或定时器,定期调用组件对象 GetState() 方法检查组
件对象的状态,如果状态 SS_STOPED 则执行重连。
2) 启动一个监测线程,在组件 OnClose 事件中向监测线程发送断线重连
Event激活监测线程,监测线程循环调用组件对象 GetState() 方法
检查组件对象的状态,直到状态为 SS_STOPED 则执行重连。
3) 使用窗口消息机制结 ::PostMessage() / ::PostThreadMessage() API 函数
替代 2) 中的监测线程和通知Event
4) HP-Socket v5.7.x 版本开始,可以使用 Wait() 方法实现重连:组 Start()
成功后启动重连检查线程,在重连检查线程中调用 Wait() 进行等待,当
Wait() 返回 TRUE 时执行重连。
Q-08
HP-Socket 有心跳检测机制吗?
A
有(UdpCast 组件除外)TCP 组件使用 TCP 协议内置的心跳检测机制,UDP
组件通过互发 0 字节数据包实现心跳检测
1) TCP 心跳检测:SetKeepAliveTime() / SetKeepAliveInterval(),单位 - 毫秒
超时时间计算公式:KeepAliveTime + (KeepAliveInterval * N)
其中 N 为固定值:WinXP 以下系统 N=5Win7 以上系统 N=10
2) UDP 心跳检测SetDetectInterval() / SetDetectAttempts(),单位 - 毫秒
超时时间计算公式:DetectInterval * (DetectAttempts + X)
其中 X 可能为 0~1 之间的任意值
3) 对于 Server Agent 组件,可以通过“断开静默连接式间接实现心跳
检测。如:使用定时器或独立线程定时调 DisconnectSilenceConnections()
方法断开静默连接。
Q-09
为什么 HP-Socket UDP 组件与我的 UDP 程序通信经常会断开连接?
A
HP-Socket UDP 服务端和客户端组件默认都开启了心跳检测机制,与第三方
UDP 程序通信时,有两种选择:
1) 调用 SetDetectInterval(0) / SetDetectAttempts(0) 关闭 UDP 组件的心跳检测
机制。
2) 你自己的程序实现 HP-Socket UDP 心跳检测握手。具体方法是
使用 IUdpClient 作为客户端:当服务端接收到 0 字节的 UDP 心跳数
据包时立刻回复一个 0 字节的握手包。
使用 IUdpServer 作为服务端:客户端需要定期向服务端发 0 字节
UDP 心跳数据包
Q-10
HP-Socket UDP Client / Server 连接关闭时对端不触发 OnClose 事件?
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
82
A
UDP 本身是无连接的通信协议,当一端关闭时对端感知不到HP-Socket v5.5.x
及其之前版本只能通过心跳机制(Q-07)或应用层实现感知;HP-Socket v5.6.x
本开始,当一端关闭时会主动向对端发送一个特殊“关闭通知”数据报,对端接
收到该数据报后会立即关闭自身。但请注意:基于 UDP 的不可靠特性,对端并不
一定能接收到“关闭通知”数据报,这种情形下还是需要通过心跳机制方式等进行
补偿。“关闭通知”数据报长度为 16 字节,内容如下
{0xBE, 0xB6, 0x1F, 0xEB, 0xDA, 0x52, 0x46, 0xBA, 0x92, 0x33, 0x59, 0xDB, 0xBF,
0xE6, 0xC8, 0xE4}
Q-11
HP-Socket TCP 组件是否处理了粘包?
A
三种选择:
1) PUSH 模型:应用程序手工处理粘包
2) PULL 模型:与应用层协议配合,半自动处理粘包。
3) PACK 模型:通信组件自动处理粘包。
Q-12
HP-Socket 如何与第三方 Socket 应用通信?
A
根据 HP-Socket 组件接收模型分别处理:
1) PUSH 模型:与应用层协议无关,可以直接通信。
2) PULL 模型:与对端协商应用层协议
3) PACK 模型:对端需遵守 HP-Socket PACK 的数据包格式。
Q-13
多个线程同时发送数据时会不会造成发送方或接收方发送数据包乱序?
A
不会。对于发送方,HP-Socket 会确保每个 Send() 方法调用所发出的数据都是
完整有序的,不会受其它 Send() 方法干扰;对于接收方,HP-Socket 对同一连接不
会同时触发多个 OnReceive 事件,因此,接收方的数据包也不会发生乱序。
Q-14
多个通信组件能共享同一个监听器对象吗?
A
可以。监听器回调事件的 pSend 参数标识当前通信组件。
Q-15
HP-Socket 如何实现流量控制?
A
可以通过数据接收和数据发送两个方面实现流量控制:
1) 数据接收:调用 PauseReceive() 方法暂停或恢复数据接收。
2) 数据接收:调用 GetPendingDataLength() 方法获取堆积的未发出数据量,
控制数据发送速度。
Q-16
对于小数据包、实时性要求高的 TCP 通信场景如何设置通信属性?
A
通过 SP_DIRECT 发送策略配合 TCP_NODELAY Socket 选项设置
1) 调用 SetSendPolicy(SP_DIRECT) 法设置直接发送策略。
2) 调用 SetNoDelay(TRUE) 方法设置 TCP_NODELAY Socket 选项
Q-17
HP-Socket 如何设置代理服务器?
A
根据不同组件类型和代理服务器类型有不同的设置方式
1) TCP 组件设置 SOCKS 理:通过 SOCKS 协议连接到代理服务器后即
项目主页 http://www.oschina.net/p/hp-socket 下载地址 https://github.com/ldcsaa/HP-Socket
83
开始正常数据通信。
2) SSL 件设置 SOCKS 代理:调用 SetSSLAutoHandShake(FALSE) 法把
组件设置为“手工启动 SSL 握手”模式,通过 SOCKS 协议连接到代理服
务器后调用 StartSSLHandShake()法启动 SSL 握手,开始正常数据通信。
3) Http/Https 组件设置 SOCKS 代理:调用 SetHttpAutoStart(FALSE) 方法把
组件设置为“手工启动 HTTP 通信模式,通过 SOCKS 协议连接到代理
服务器后调用 StartHttp()法启动 HTTP 通信。
4) Http 组件设 HTTP 代理不必做任何额外工作,只需把连接地址设置为
代理服务器地址,发送请求时指定“Host”请求头为目标服务器地址。
5) Https 组件设 HTTP Tunnel 代理:调用 SetSSLAutoHandShake(FALSE)
SSL
CONNECT请求,请求成功后调 StartSSLHandShake()方法启 SSL
握手,开始正常数据通信
Q-18
如何减少库文件的体积?
A
HP-Socket 发布包提供的库文件包含了所有组件和功能特性,如果不需要某些
组件或功能特性可以在 include/hpsocket/HPTypeDef.h 中定义相应编译指示宏重新
编译库文件(注意:修改后的 include/hpsocket/HPTypeDef.h
include/hpsocket/hpsocket/ HPTypeDef.h
1) _UDP_DISABLED 排除 UDP 组件
2) _SSL_DISABLED 排除 SSL 组件(包括 Https 组件)
3) _HTTP_DISABLED 排除 HTTP 组件(包 Https 组件)
4) _ZLIB_DISABLED :排除 zlib 相关功能函数。
5) _BROTLI_DISABLED :排除 brotli 相关功能函数。
6) _ICONV_DISABLED 排除 iconv 相关功能函数(只对 Linux 有效)