HPSocket服务Demo学习
最近偶尔接触到HPSocket框架,并找到官方的demo:
想要快速的上手使用,方法很简单,分几步就完成。
- 找到HPSocket的共享文件库,这个库里面包含了Client和Server端需要用的API和公共文件,将这个库移植到需要实现的工程内部。
- 根据工程目录编写makefile,生成对象文件。
附简单Demo代码(转载自git,测试可用):
说明
修改IP和port在helper.h内宏定义
调库使用说明在SocketHelper.h,一些常用套接字也有帮助方法
SocketHelper.h
/*
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
*
* Author : Bruce Liang
* Website : http://www.jessma.org
* Project : https://github.com/ldcsaa
* Blog : http://www.cnblogs.com/ldcsaa
* Wiki : http://www.oschina.net/p/hp-socket
* QQ Group : 75375912, 44636872
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "HPTypeDef.h"
#include "SocketInterface.h"
#include "common/StringT.h"
#include "common/SysHelper.h"
#include "common/BufferPtr.h"
#include "common/BufferPool.h"
#include "common/RingBuffer.h"
#include "common/FileHelper.h"
#include <netdb.h>
#include <sys/un.h>
#include <sys/socket.h>
using ADDRESS_FAMILY = sa_family_t;
using IN_ADDR = in_addr;
using IN6_ADDR = in6_addr;
using SOCKADDR = sockaddr;
using SOCKADDR_IN = sockaddr_in;
using SOCKADDR_IN6 = sockaddr_in6;
/************************************************************************
名称:全局常量
描述:声明组件的公共全局常量
************************************************************************/
/* Socket 缓冲区最小值 */
#define MIN_SOCKET_BUFFER_SIZE 8
/* 小文件最大字节数 */
#define MAX_SMALL_FILE_SIZE 0x3FFFFF
/* 最大连接时长 */
#define MAX_CONNECTION_PERIOD (MAXINT / 2)
/* 处理接收事件时最大读取次数 */
#define MAX_CONTINUE_READS 30
/* 处理发送事件时最大写入次数 */
#define MAX_CONTINUE_WRITES 50
/* 默认工作队列等待的最大描述符事件数量 */
#define DEFAULT_WORKER_MAX_EVENT_COUNT CIODispatcher::DEF_WORKER_MAX_EVENTS
/* Server/Agent 默认最大连接数 */
#define DEFAULT_MAX_CONNECTION_COUNT 10000
/* Server/Agent 默认 Socket 缓存对象锁定时间 */
#define DEFAULT_FREE_SOCKETOBJ_LOCK_TIME (10 * 1000)
/* Server/Agent 默认 Socket 缓存池大小 */
#define DEFAULT_FREE_SOCKETOBJ_POOL 150
/* Server/Agent 默认 Socket 缓存池回收阀值 */
#define DEFAULT_FREE_SOCKETOBJ_HOLD 600
/* Server/Agent 默认内存块缓存池大小 */
#define DEFAULT_FREE_BUFFEROBJ_POOL 300
/* Server/Agent 默认内存块缓存池回收阀值 */
#define DEFAULT_FREE_BUFFEROBJ_HOLD 1200
/* Client 默认内存块缓存池大小 */
#define DEFAULT_CLIENT_FREE_BUFFER_POOL_SIZE 10
/* Client 默认内存块缓存池回收阀值 */
#define DEFAULT_CLIENT_FREE_BUFFER_POOL_HOLD 40
/* IPv4 默认绑定地址 */
#define DEFAULT_IPV4_BIND_ADDRESS _T("0.0.0.0")
/* IPv6 默认绑定地址 */
#define DEFAULT_IPV6_BIND_ADDRESS _T("::")
/* TCP 默认通信数据缓冲区大小 */
#define DEFAULT_TCP_SOCKET_BUFFER_SIZE DEFAULT_BUFFER_SIZE
/* TCP 默认心跳包间隔 */
#define DEFALUT_TCP_KEEPALIVE_TIME (30 * 1000)
/* TCP 默认心跳确认包检测间隔 */
#define DEFALUT_TCP_KEEPALIVE_INTERVAL (10 * 1000)
/* TCP Server 默认 Listen 队列大小 */
#define DEFAULT_TCP_SERVER_SOCKET_LISTEN_QUEUE SOMAXCONN
/* UDP 默认数据报文最大长度 */
#define DEFAULT_UDP_MAX_DATAGRAM_SIZE 1472
/* UDP 默认 Receive 预投递数量 */
#define DEFAULT_UDP_POST_RECEIVE_COUNT DEFAULT_WORKER_MAX_EVENT_COUNT
/* UDP 默认监测包尝试次数 */
#define DEFAULT_UDP_DETECT_ATTEMPTS 3
/* UDP 默认监测包发送间隔 */
#define DEFAULT_UDP_DETECT_INTERVAL 30
/* TCP Pack 包长度位数 */
#define TCP_PACK_LENGTH_BITS 22
/* TCP Pack 包长度掩码 */
#define TCP_PACK_LENGTH_MASK 0x3FFFFF
/* TCP Pack 包最大长度硬限制 */
#define TCP_PACK_MAX_SIZE_LIMIT 0x3FFFFF
/* TCP Pack 包默认最大长度 */
#define TCP_PACK_DEFAULT_MAX_SIZE 0x040000
/* TCP Pack 包头标识值硬限制 */
#define TCP_PACK_HEADER_FLAG_LIMIT 0x0003FF
/* TCP Pack 包头默认标识值 */
#define TCP_PACK_DEFAULT_HEADER_FLAG 0x000000
#define PORT_SEPARATOR_CHAR ':'
#define IPV6_ADDR_BEGIN_CHAR '['
#define IPV6_ADDR_END_CHAR ']'
#define IPV4_ADDR_SEPARATOR_CHAR '.'
#define IPV6_ADDR_SEPARATOR_CHAR ':'
#define IPV6_ZONE_INDEX_CHAR '%'
#define INVALID_SOCKET INVALID_FD
#define SOCKET_ERROR HAS_ERROR
#define WSASetLastError SetLastError
#define WSAGetLastError GetLastError
#define InetPton inet_pton
#define InetNtop inet_ntop
#define closesocket close
typedef struct hp_addr
{
ADDRESS_FAMILY family;
union
{
ULONG_PTR addr;
IN_ADDR addr4;
IN6_ADDR addr6;
};
static const hp_addr ANY_ADDR4;
static const hp_addr ANY_ADDR6;
inline int AddrSize() const
{
return AddrSize(family);
}
inline static int AddrSize(ADDRESS_FAMILY f)
{
if(f == AF_INET)
return sizeof(IN_ADDR);
return sizeof(IN6_ADDR);
}
inline static const hp_addr& AnyAddr(ADDRESS_FAMILY f)
{
if(f == AF_INET)
return ANY_ADDR4;
return ANY_ADDR6;
}
inline const ULONG_PTR* Addr() const {return &addr;}
inline ULONG_PTR* Addr() {return &addr;}
inline BOOL IsIPv4() const {return family == AF_INET;}
inline BOOL IsIPv6() const {return family == AF_INET6;}
inline BOOL IsSpecified() const {return IsIPv4() || IsIPv6();}
inline void ZeroAddr() {::ZeroMemory(&addr6, sizeof(addr6));}
inline void Reset() {::ZeroMemory(this, sizeof(*this));}
inline hp_addr& Copy(hp_addr& other) const
{
if(this != &other)
memcpy(&other, this, offsetof(hp_addr, addr) + AddrSize());
return other;
}
hp_addr(ADDRESS_FAMILY f = AF_UNSPEC, BOOL bZeroAddr = FALSE)
{
family = f;
if(bZeroAddr) ZeroAddr();
}
} HP_ADDR, *HP_PADDR;
typedef struct hp_sockaddr
{
union
{
ADDRESS_FAMILY family;
SOCKADDR addr;
SOCKADDR_IN addr4;
SOCKADDR_IN6 addr6;
};
inline int AddrSize() const
{
return AddrSize(family);
}
inline static int AddrSize(ADDRESS_FAMILY f)
{
if(f == AF_INET)
return sizeof(SOCKADDR_IN);
return sizeof(SOCKADDR_IN6);
}
inline static const hp_sockaddr& AnyAddr(ADDRESS_FAMILY f)
{
static const hp_sockaddr s_any_addr4(AF_INET, TRUE);
static const hp_sockaddr s_any_addr6(AF_INET6, TRUE);
if(f == AF_INET)
return s_any_addr4;
return s_any_addr6;
}
inline static int AddrMinStrLength(ADDRESS_FAMILY f)
{
if(f == AF_INET)
return 16;
return 46;
}
inline BOOL IsIPv4() const {return family == AF_INET;}
inline BOOL IsIPv6() const {return family == AF_INET6;}
inline BOOL IsSpecified() const {return IsIPv4() || IsIPv6();}
inline USHORT Port() const {return ntohs(addr4.sin_port);}
inline void SetPort(USHORT usPort) {addr4.sin_port = htons(usPort);}
inline void* SinAddr() const {return IsIPv4() ? (void*)&addr4.sin_addr : (void*)&addr6.sin6_addr;}
inline void* SinAddr() {return IsIPv4() ? (void*)&addr4.sin_addr : (void*)&addr6.sin6_addr;}
inline const SOCKADDR* Addr() const {return &addr;}
inline SOCKADDR* Addr() {return &addr;}
inline void ZeroAddr() {::ZeroMemory(((char*)this) + sizeof(family), sizeof(*this) - sizeof(family));}
inline void Reset() {::ZeroMemory(this, sizeof(*this));}
inline hp_sockaddr& Copy(hp_sockaddr& other) const
{
if(this != &other)
memcpy(&other, this, AddrSize());
return other;
}
size_t Hash() const
{
ASSERT(IsSpecified());
if(IsIPv4())
return ((addr4.sin_family << 16) | addr4.sin_port) ^ addr4.sin_addr.s_addr;
else
{
ULONG* p = (ULONG*)(((char*)this) + offsetof(SOCKADDR_IN6, sin6_addr));
return ((addr6.sin6_family << 16) | addr6.sin6_port) ^ addr6.sin6_flowinfo ^ p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4];
}
}
bool EqualTo(const hp_sockaddr& other) const
{
ASSERT(IsSpecified() && other.IsSpecified());
if(IsIPv4())
return EqualMemory(this, &other, offsetof(SOCKADDR_IN, sin_zero));
else
return EqualMemory(this, &other, sizeof(addr6));
}
hp_sockaddr(ADDRESS_FAMILY f = AF_UNSPEC, BOOL bZeroAddr = FALSE)
{
family = f;
if(bZeroAddr) ZeroAddr();
}
} HP_SOCKADDR, *HP_PSOCKADDR;
/* Server 组件和 Agent 组件内部使用的事件处理结果常量 */
// 连接已关闭
#define HR_CLOSED 0xFF
/* 命令类型 */
enum EnDispCmdType
{
DISP_CMD_SEND = 0x01, // 发送数据
DISP_CMD_RECEIVE = 0x02, // 接收数据
DISP_CMD_UNPAUSE = 0x03, // 恢复接收数据
DISP_CMD_DISCONNECT = 0x04 // 断开连接
};
/* 关闭连接标识 */
enum EnSocketCloseFlag
{
SCF_NONE = 0, // 不触发事件
SCF_CLOSE = 1, // 触发 正常关闭 OnClose 事件
SCF_ERROR = 2 // 触发 异常关闭 OnClose 事件
};
/* 数据缓冲节点 */
typedef TItem TBufferObj;
/* 数据缓冲区对象池 */
typedef CItemPool CBufferObjPool;
/* 数据缓冲区链表模板 */
typedef TItemListExV TBufferObjList;
/* 线程 ID - 接收缓冲区哈希表 */
typedef unordered_map<THR_ID, CBufferPtr*> TReceiveBufferMap;
/* 线程 ID - 接收缓冲区哈希表迭代器 */
typedef TReceiveBufferMap::iterator TReceiveBufferMapI;
/* 线程 ID - 接收缓冲区哈希表 const 迭代器 */
typedef TReceiveBufferMap::const_iterator TReceiveBufferMapCI;
/* Socket 缓冲区基础结构 */
struct TSocketObjBase
{
CONNID connID;
HP_SOCKADDR remoteAddr;
PVOID extra;
PVOID reserved;
PVOID reserved2;
BOOL valid;
DWORD activeTime;
union
{
DWORD freeTime;
DWORD connTime;
};
volatile BOOL paused;
TBufferObjList sndBuff;
CReentrantCriSec csSend;
TSocketObjBase(CBufferObjPool& bfPool)
: sndBuff(bfPool)
{
}
static BOOL IsExist(TSocketObjBase* pSocketObj)
{return pSocketObj != nullptr;}
static BOOL IsValid(TSocketObjBase* pSocketObj)
{return pSocketObj != nullptr && pSocketObj->valid;}
static void Invalid(TSocketObjBase* pSocketObj)
{ASSERT(IsExist(pSocketObj)); pSocketObj->valid = FALSE;}
static void Release(TSocketObjBase* pSocketObj)
{
ASSERT(IsExist(pSocketObj));
pSocketObj->freeTime = ::TimeGetTime();
pSocketObj->sndBuff.Release();
}
int Pending() {return sndBuff.Length();}
BOOL IsPending() {return Pending() > 0;}
BOOL IsPaused() {return paused;}
void Reset(CONNID dwConnID)
{
connID = dwConnID;
valid = TRUE;
paused = FALSE;
extra = nullptr;
reserved = nullptr;
reserved2 = nullptr;
}
};
/* 数据缓冲区结构 */
struct TSocketObj : public TSocketObjBase
{
using __super = TSocketObjBase;
SOCKET socket;
CReentrantSpinGuard csIo;
TSocketObj(CBufferObjPool& bfPool)
: __super(bfPool)
{
}
static BOOL InvalidSocketObj(TSocketObj* pSocketObj)
{
BOOL bDone = FALSE;
if(TSocketObjBase::IsValid(pSocketObj))
{
CReentrantSpinLock locallock(pSocketObj->csIo);
CReentrantCriSecLock locallock2(pSocketObj->csSend);
if(TSocketObjBase::IsValid(pSocketObj))
{
TSocketObjBase::Invalid(pSocketObj);
bDone = TRUE;
}
}
return bDone;
}
void Reset(CONNID dwConnID, SOCKET soClient)
{
__super::Reset(dwConnID);
socket = soClient;
}
};
/* Agent 数据缓冲区结构 */
struct TAgentSocketObj : public TSocketObj
{
using __super = TSocketObj;
CStringA host;
BOOL connected;
TAgentSocketObj(CBufferObjPool& bfPool)
: __super(bfPool)
{
}
void Reset(CONNID dwConnID, SOCKET soClient)
{
__super::Reset(dwConnID, soClient);
host.Empty();
connected = FALSE;
}
BOOL GetRemoteHost(LPCSTR* lpszHost, USHORT* pusPort = nullptr)
{
*lpszHost = host;
if(pusPort)
*pusPort = remoteAddr.Port();
return (!host.IsEmpty());
}
BOOL HasConnected()
{
return connected;
}
VOID SetConnected(BOOL bConnected = TRUE)
{
connected = bConnected;
}
};
/* UDP 数据缓冲区结构 */
struct TUdpSocketObj : public TSocketObjBase
{
using __super = TSocketObjBase;
using CRecvQueue = CCASQueue<TItem>;
CRecvQueue recvQueue;
volatile DWORD detectFails;
CSimpleRWLock lcIo;
CBufferObjPool& itPool;
TUdpSocketObj(CBufferObjPool& bfPool)
: __super(bfPool), itPool(bfPool)
{
}
~TUdpSocketObj()
{
ClearRecvQueue();
}
BOOL HasRecvData() {return !recvQueue.IsEmpty();}
static BOOL InvalidSocketObj(TUdpSocketObj* pSocketObj)
{
BOOL bDone = FALSE;
if(TSocketObjBase::IsValid(pSocketObj))
{
CWriteLock locallock(pSocketObj->lcIo);
CReentrantCriSecLock locallock2(pSocketObj->csSend);
if(TSocketObjBase::IsValid(pSocketObj))
{
TSocketObjBase::Invalid(pSocketObj);
bDone = TRUE;
}
}
return bDone;
}
void Reset(CONNID dwConnID)
{
__super::Reset(dwConnID);
detectFails = 0;
}
static void Release(TUdpSocketObj* pSocketObj)
{
__super::Release(pSocketObj);
pSocketObj->ClearRecvQueue();
}
void ClearRecvQueue()
{
TItem* pItem = nullptr;
while(recvQueue.PopFront(&pItem))
itPool.PutFreeItem(pItem);
VERIFY(recvQueue.IsEmpty());
}
};
/* 有效 TSocketObj 缓存 */
typedef CRingCache2<TSocketObj, CONNID, true> TSocketObjPtrPool;
/* 失效 TSocketObj 缓存 */
typedef CRingPool<TSocketObj> TSocketObjPtrList;
/* 失效 TSocketObj 垃圾回收结构链表 */
typedef CCASQueue<TSocketObj> TSocketObjPtrQueue;
/* 有效 TSocketObj 缓存 */
typedef CRingCache2<TAgentSocketObj, CONNID, true> TAgentSocketObjPtrPool;
/* 失效 TSocketObj 缓存 */
typedef CRingPool<TAgentSocketObj> TAgentSocketObjPtrList;
/* 失效 TSocketObj 垃圾回收结构链表 */
typedef CCASQueue<TAgentSocketObj> TAgentSocketObjPtrQueue;
/* 有效 TUdpSocketObj 缓存 */
typedef CRingCache2<TUdpSocketObj, CONNID, true> TUdpSocketObjPtrPool;
/* 失效 TUdpSocketObj 缓存 */
typedef CRingPool<TUdpSocketObj> TUdpSocketObjPtrList;
/* 失效 TUdpSocketObj 垃圾回收结构链表 */
typedef CCASQueue<TUdpSocketObj> TUdpSocketObjPtrQueue;
/* HP_SOCKADDR 比较器 */
struct hp_sockaddr_func
{
struct hash
{
size_t operator() (const HP_SOCKADDR* pA) const
{
return pA->Hash();
}
};
struct equal_to
{
bool operator () (const HP_SOCKADDR* pA, const HP_SOCKADDR* pB) const
{
return pA->EqualTo(*pB);
}
};
};
/* 地址-连接 ID 哈希表 */
typedef unordered_map<const HP_SOCKADDR*, CONNID, hp_sockaddr_func::hash, hp_sockaddr_func::equal_to>
TSockAddrMap;
/* 地址-连接 ID 哈希表迭代器 */
typedef TSockAddrMap::iterator TSockAddrMapI;
/* 地址-连接 ID 哈希表 const 迭代器 */
typedef TSockAddrMap::const_iterator TSockAddrMapCI;
/* IClient 组件关闭上下文 */
struct TClientCloseContext
{
BOOL bFireOnClose;
EnSocketOperation enOperation;
int iErrorCode;
TClientCloseContext(BOOL bFire = TRUE, EnSocketOperation enOp = SO_CLOSE, int iCode = SE_OK)
{
Reset(bFire, enOp, iCode);
}
void Reset(BOOL bFire = TRUE, EnSocketOperation enOp = SO_CLOSE, int iCode = SE_OK)
{
bFireOnClose = bFire;
enOperation = enOp;
iErrorCode = iCode;
}
};
/*****************************************************************************************************/
/******************************************** 公共帮助方法 ********************************************/
/*****************************************************************************************************/
/* 获取错误描述文本 */
LPCTSTR GetSocketErrorDesc(EnSocketError enCode);
/* 确定地址簇 */
ADDRESS_FAMILY DetermineAddrFamily(LPCTSTR lpszAddress);
/* 地址字符串地址转换为 HP_ADDR */
BOOL GetInAddr(LPCTSTR lpszAddress, HP_ADDR& addr);
/* 地址字符串地址转换为 HP_SOCKADDR */
BOOL GetSockAddr(LPCTSTR lpszAddress, USHORT usPort, HP_SOCKADDR& addr);
/* 检查字符串是否符合 IP 地址格式 */
BOOL IsIPAddress(LPCTSTR lpszAddress, EnIPAddrType* penType = nullptr);
/* 通过主机名获取 IP 地址 */
BOOL GetIPAddress(LPCTSTR lpszHost, LPTSTR lpszIP, int& iIPLenth, EnIPAddrType& enType);
/* 通过主机名获取 HP_SOCKADDR */
BOOL GetSockAddrByHostName(LPCTSTR lpszHost, USHORT usPort, HP_SOCKADDR& addr);
/* 通过主机名获取 HP_SOCKADDR */
BOOL GetSockAddrByHostNameDirectly(LPCTSTR lpszHost, USHORT usPort, HP_SOCKADDR &addr);
/* 枚举主机 IP 地址 */
BOOL EnumHostIPAddresses(LPCTSTR lpszHost, EnIPAddrType enType, LPTIPAddr** lpppIPAddr, int& iIPAddrCount);
/* 填充 LPTIPAddr* */
BOOL RetrieveSockAddrIPAddresses(const vector<HP_PSOCKADDR>& vt, LPTIPAddr** lpppIPAddr, int& iIPAddrCount);
/* 释放 LPTIPAddr* */
BOOL FreeHostIPAddresses(LPTIPAddr* lppIPAddr);
/* 把 HP_SOCKADDR 结构转换为地址字符串 */
BOOL sockaddr_IN_2_A(const HP_SOCKADDR& addr, ADDRESS_FAMILY& usFamily, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort);
/* 把地址字符串转换为 HP_SOCKADDR 结构 */
BOOL sockaddr_A_2_IN(LPCTSTR lpszAddress, USHORT usPort, HP_SOCKADDR& addr);
/* 获取 Socket 的本地或远程地址信息 */
BOOL GetSocketAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort, BOOL bLocal = TRUE);
/* 获取 Socket 的本地地址信息 */
BOOL GetSocketLocalAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort);
/* 获取 Socket 的远程地址信息 */
BOOL GetSocketRemoteAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort);
/* 64 位网络字节序转主机字节序 */
ULONGLONG NToH64(ULONGLONG value);
/* 64 位主机字节序转网络字节序 */
ULONGLONG HToN64(ULONGLONG value);
HRESULT ReadSmallFile(LPCTSTR lpszFileName, CFile& file, CFileMapping& fmap, DWORD dwMaxFileSize = MAX_SMALL_FILE_SIZE);
HRESULT MakeSmallFilePackage(LPCTSTR lpszFileName, CFile& file, CFileMapping& fmap, WSABUF szBuf[3], const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr);
/************************************************************************
名称:setsockopt() 帮助方法
描述:简化常用的 setsockopt() 调用
************************************************************************/
int SSO_SetSocketOption (SOCKET sock, int level, int name, LPVOID val, int len);
int SSO_GetSocketOption (SOCKET sock, int level, int name, LPVOID val, int* len);
int SSO_IoctlSocket (SOCKET sock, long cmd, PVOID arg);
int SSO_NoBlock (SOCKET sock, BOOL bNoBlock = TRUE);
int SSO_NoDelay (SOCKET sock, BOOL bNoDelay = TRUE);
int SSO_DontLinger (SOCKET sock, BOOL bDont = TRUE);
int SSO_Linger (SOCKET sock, int l_onoff, int l_linger);
int SSO_KeepAlive (SOCKET sock, BOOL bKeepAlive = TRUE);
int SSO_KeepAliveVals (SOCKET sock, BOOL bOnOff, DWORD dwIdle, DWORD dwInterval, DWORD dwCount = 5);
int SSO_ReuseAddress (SOCKET sock, BOOL bReuse = TRUE);
int SSO_RecvBuffSize (SOCKET sock, int size);
int SSO_SendBuffSize (SOCKET sock, int size);
int SSO_RecvTimeout (SOCKET sock, int sec, int microsec = 0);
int SSO_SendTimeout (SOCKET sock, int sec, int microsec = 0);
int SSO_GetError (SOCKET sock);
/* 生成 Connection ID */
CONNID GenerateConnectionID();
/* 关闭 Socket */
int ManualCloseSocket(SOCKET sock, int iShutdownFlag = 0xFF, BOOL bGraceful = TRUE, BOOL bReuseAddress = FALSE);
helper.h
#pragma once
#include "../hpsocket/HPTypeDef.h"
#include "../hpsocket/common/GeneralHelper.h"
#include <cstdio>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <sys/socket.h>
#define EVT_ON_SEND _T("OnSend")
#define EVT_ON_RECEIVE _T("OnReceive")
#define EVT_ON_CLOSE _T("OnClose")
#define EVT_ON_ERROR _T("OnError")
#define EVT_ON_PREPARE_CONNECT _T("OnPrepareConnect")
#define EVT_ON_PREPARE_LISTEN _T("OnPrepareListen")
#define EVT_ON_ACCEPT _T("OnAccept")
#define EVT_ON_CONNECT _T("OnConnect")
#define EVT_ON_HAND_SHAKE _T("OnHandShake")
#define EVT_ON_SHUTDOWN _T("OnShutdown")
#define EVT_ON_END_TEST _T("END TEST")
#define EVT_ON_STAT_TEST _T("STAT TEST")
#define EVT_ON_MESSAGE_BEGIN _T("OnMessageBegin")
#define EVT_ON_REQUEST_LINE _T("OnRequestLine")
#define EVT_ON_STATUS_LINE _T("OnStatusLine")
#define EVT_ON_HEADER _T("OnHeader")
#define EVT_ON_HEADERS_COMPLETE _T("OnHeadersComplete")
#define EVT_ON_BODY _T("OnBody")
#define EVT_ON_CHUNK_HEADER _T("OnChunkHeader")
#define EVT_ON_CHUNK_COMPLETE _T("OnChunkComplete")
#define EVT_ON_MESSAGE_COMPLETE _T("OnMessageComplete")
#define EVT_ON_UPGRADE _T("OnUpgrade")
#define EVT_ON_PARSE_ERROR _T("OnParseError")
#define EVT_ON_WS_MSG_HEADER _T("OnWSMessageHeader")
#define EVT_ON_WS_MSG_BODY _T("OnWSMessageBody")
#define EVT_ON_WS_MSG_COMPLETE _T("OnWSMessageComplete")
#define EVT_ON_UNCOMPRESS_BODY _T("Uncompress Body")
#define EVT_ON_UNCOMPRESS_BODY_FAIL _T("Uncompress Body Fail")
#define IPV4_LOOPBACK_ADDRESS _T("127.0.0.1")
#define IPV6_LOOPBACK_ADDRESS _T("::1")
#define IPV4_ANY_ADDRESS _T("0.0.0.0")
#define IPV6_ANY_ADDRESS _T("::")
#define DEF_BROAD_CAST_ADDRESS _T("233.0.0.1")
#define DEF_TCP_UDP_PORT 5555
#define DEF_HTTP_PORT 8080
#define DEF_HTTPS_PORT 8443
#define TCP_KEEPALIVE_TIME (30 * 1000)
#define UDP_DETECT_ATTEMPTS 3
enum EnAppState
{
ST_STARTING, ST_STARTED, ST_CONNECTING, ST_CONNECTED, ST_STOPPING, ST_STOPPED
};
struct app_arg
{
static char OPTIONS[];
// -a
CString remote_addr;
// -b
CString bind_addr;
// -p
USHORT port;
// -j
CString reject_addr;
// -n
bool async;
// -t
DWORD thread_count;
// -e
DWORD test_times;
// -i
DWORD test_interval;
// -c
DWORD conn_count;
// -l
DWORD data_length;
// -s
EnSendPolicy send_policy;
// -m
DWORD max_conn;
// -q
bool keep_alive;
// -o
EnCastMode cast_mode;
// -r
bool reuse_addr;
// -u
bool ip_loop;
// -z
int ttl;
// -x port1[,port2]
USHORT http_port1;
// -x port1[,port2]
USHORT http_port2;
// -y
bool http_secure;
// -d
CString http_method;
// -f
CString http_req_path;
// -k
bool http_use_cookie;
// -w
bool http_with_listener;
public:
void ParseArgs(int argc, char* const argv[]);
void ShowPFMTestArgs(BOOL bAgent);
static void PrintUsage();
static void PrintVersion();
public:
app_arg();
~app_arg();
};
extern app_arg g_app_arg;
class CAppSignalHandler
{
public:
CAppSignalHandler(const vector<int>&& signals, BOOL bIgnoreSigInt = TRUE)
: m_bIgnoreSigInt(bIgnoreSigInt)
{
sigset_t ss;
sigemptyset(&ss);
for(size_t i = 0; i < signals.size(); i++)
sigaddset(&ss, signals[i]);
sh.Setup(this, &CAppSignalHandler::handle_sig, &ss);
}
int WaitForExit()
{
int rs = evt.Wait();
PRINTLN(" bye ~ bye ~");
return rs;
}
private:
void handle_sig(const siginfo_t* pSigInfo)
{
if(pSigInfo->si_signo == SIGINT)
m_bIgnoreSigInt || evt.Set();
}
private:
CSignalHandler<CAppSignalHandler> sh;
CPipeEvent evt;
BOOL m_bIgnoreSigInt;
};
class CTermAttrInitializer
{
public:
CTermAttrInitializer(tcflag_t l_mask = 0)
{
tcgetattr(STDIN_FILENO, &old_attr);
termios new_attr = old_attr;
new_attr.c_lflag &= ~l_mask;
new_attr.c_cc[VERASE]= 0x08;
new_attr.c_cc[VTIME] = 0;
new_attr.c_cc[VMIN] = 1;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_attr);
}
~CTermAttrInitializer() {tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_attr);}
private:
termios old_attr;
};
class CCommandParser
{
public:
using CMD_FUNC = void (*)(CCommandParser*);
enum EnAppType {AT_SERVER, AT_AGENT, AT_CLIENT};
enum EnCmdType {CT_START = 0, CT_STOP, CT_STATUS, CT_CONNECT, CT_SEND, CT_PAUSE, CT_KICK, CT_KICK_L, CT_KICK_S, CT_STAT, CT_MAX};
private:
struct TCmdNameFunc
{
LPCTSTR name;
CMD_FUNC func;
};
public:
BOOL Run();
void PrintStatus(EnServiceState enStatus);
public:
CCommandParser(EnAppType enAppType, CMD_FUNC fnCmds[CT_MAX]);
~CCommandParser() {}
private:
BOOL WaitForExit();
void WorkerProc(PVOID pv);
void Parse(LPTSTR lpszLine, SSIZE_T nSize);
void ParseCmdArgs(EnCmdType type, LPTSTR lpszArg);
void Reset();
void PrintUsage();
CString GetCmdUsage(EnCmdType type);
public:
BOOL m_bFlag;
CONNID m_dwConnID;
CString m_strMessage;
CString m_strRemoteAddr;
USHORT m_usRemotePort;
DWORD m_dwSeconds;
private:
EnAppType m_enAppType;
TCmdNameFunc m_szCmdNameFuncs[CT_MAX];
CThread<CCommandParser, VOID, VOID> m_thWorker;
};
struct server_statistics_info
{
volatile LONG m_lClientCount;
volatile LONGLONG m_llTotalReceived;
volatile LONGLONG m_llTotalSent;
CCriSec m_cs;
void Reset(BOOL bResetClientCount = TRUE);
void CheckClientCount();
void CheckStatistics();
void AddTotalRecv(int iLength);
void AddTotalSend(int iLength);
};
struct client_statistics_info
{
volatile LONGLONG m_llTotalReceived;
volatile LONGLONG m_llTotalSent;
LONGLONG m_llExpectReceived;
DWORD m_dwBeginTickCount;
DWORD m_dwTimeconsuming;
void Reset();
void StartTest();
void CheckStatistics();
void AddTotalRecv(int iLength);
void AddTotalSend(int iLength);
};
struct info_msg
{
LPCTSTR name;
CONNID connID;
LPCTSTR evt;
int contentLength;
LPCTSTR content;
static info_msg* Construct(CONNID dwConnID, LPCTSTR lpszEvent, int iContentLength = 0, LPCTSTR lpszContent = nullptr, LPCTSTR lpszName = nullptr);
static void Destruct(info_msg* pMsg);
private:
info_msg(CONNID dwConnID, LPCTSTR lpszEvent, int iContentLength = 0, LPCTSTR lpszContent = nullptr, LPCTSTR lpszName = nullptr);
~info_msg();
};
struct TPkgHeader
{
DWORD seq;
int body_len;
};
struct TPkgBody
{
char name[30];
short age;
char desc[1];
};
struct TPkgInfo
{
bool is_header;
int length;
TPkgInfo(bool header = true, int len = sizeof(TPkgHeader)) : is_header(header), length(len) {}
void Reset() {is_header = true, length = sizeof(TPkgHeader);}
~TPkgInfo() {}
};
inline TPkgInfo* ConstructPkgInfo()
{
return new TPkgInfo(true, sizeof(TPkgHeader));
}
inline void DestructPkgInfo(TPkgInfo* pInfo)
{
delete pInfo;
}
template<class T, typename = enable_if_t<!is_void<decay_t<T>>::value>>
inline TPkgInfo* CreatePkgInfo(T* pSender, CONNID dwConnID)
{
TPkgInfo* pInfo = ConstructPkgInfo();
pSender->SetConnectionExtra(dwConnID, pInfo);
return pInfo;
}
template<class T, typename = enable_if_t<!is_void<decay_t<T>>::value>>
inline TPkgInfo* FindPkgInfo(T* pSender, CONNID dwConnID)
{
PVOID pInfo = nullptr;
pSender->GetConnectionExtra(dwConnID, &pInfo);
return (TPkgInfo*)pInfo;
}
template<class T, typename = enable_if_t<!is_void<decay_t<T>>::value>>
inline void RemovePkgInfo(T* pSender, CONNID dwConnID)
{
TPkgInfo* pInfo = FindPkgInfo(pSender, dwConnID);
ASSERT(pInfo != nullptr);
DestructPkgInfo(pInfo);
}
CBufferPtr* GeneratePkgBuffer(DWORD seq, LPCTSTR lpszName, short age, LPCTSTR lpszDesc);
CBufferPtr* GeneratePkgBuffer(const TPkgHeader& header, const TPkgBody& body);
sa_family_t GuessAddrFamily(LPCTSTR lpszAddress);
LPCTSTR GetLoopbackAddress(LPCTSTR lpszLikeAddress);
LPCTSTR GetAnyAddress(LPCTSTR lpszLikeAddress);
void LogServerStart(LPCTSTR lpszAddress, USHORT port, LPCTSTR lpszName = nullptr);
void LogServerStartFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogServerStop(LPCTSTR lpszName = nullptr);
void LogServerStopFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogAgentStart(LPCTSTR lpszAddress, BOOL bAsync, LPCTSTR lpszName = nullptr);
void LogAgentStarting(LPCTSTR lpszAddress, BOOL bAsync, LPCTSTR lpszName = nullptr);
void LogAgentStartFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogAgentStopping(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogAgentStop(LPCTSTR lpszName = nullptr);
void LogAgentStopFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogAgentSendFail(int iSequence, int iSocketIndex, DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogClientStart(LPCTSTR lpszAddress, USHORT port, LPCTSTR lpszName = nullptr);
void LogClientStarting(LPCTSTR lpszAddress, USHORT port, LPCTSTR lpszName = nullptr);
void LogClientStartFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogClientStopping(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogClientStop(LPCTSTR lpszName = nullptr);
void LogClientStopFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogClientSendFail(int iSequence, int iSocketIndex, DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogSend(CONNID dwConnID, LPCTSTR lpszContent, LPCTSTR lpszName = nullptr);
void LogSendFail(CONNID dwConnID, DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogDisconnect(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogDisconnectFail(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogDisconnect2(CONNID dwConnID, BOOL bForce, LPCTSTR lpszName = nullptr);
void LogDisconnectFail2(CONNID dwConnID, BOOL bForce, LPCTSTR lpszName = nullptr);
void LogPause(CONNID dwConnID, BOOL bPause, LPCTSTR lpszName = nullptr);
void LogPauseFail(CONNID dwConnID, BOOL bPause, LPCTSTR lpszName = nullptr);
void LogConnect(LPCTSTR lpszAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
void LogConnectFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
void LogRelease(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogReleaseFail(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogDetect(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogDetectFail(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogOnConnect(CONNID dwConnID, const CString& strAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
void LogOnConnect2(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogOnConnect3(CONNID dwConnID, const CString& strAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
void LogOnHandShake2(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void LogOnClose(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostOnSend(CONNID dwConnID, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
void PostOnReceive(CONNID dwConnID, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
void PostOnReceiveCast(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
void PostOnClose(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostOnError(CONNID dwConnID, int enOperation, int iErrorCode, LPCTSTR lpszName = nullptr);
void PostOnAccept(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, BOOL bPass, LPCTSTR lpszName = nullptr);
void PostOnAccept2(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostOnHandShake(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostOnPrepareListen(LPCTSTR lpszAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
void PostOnPrepareConnect(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostOnConnect(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
void PostOnConnect2(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
void PostOnConnect3(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostOnShutdown(LPCTSTR lpszName = nullptr);
void PostServerStatics(const LONGLONG& llTotalSent, const LONGLONG& llTotalReceived, LPCTSTR lpszName = nullptr);
void PostServerTemporaryStatics(const LONGLONG& llTotalSent, const LONGLONG& llTotalReceived, LPCTSTR lpszName = nullptr);
void PostTimeConsuming(DWORD dwTickCount, LPCTSTR lpszName = nullptr);
void PostOnMessageBegin(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostOnRequestLine(CONNID dwConnID, LPCSTR lpszMethod, USHORT usUrlFieldSet, LPCSTR lpszUrl, LPCTSTR lpszName = nullptr);
void PostOnStatusLine(CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc, LPCTSTR lpszName = nullptr);
void PostOnHeader(CONNID dwConnID, LPCSTR lpszHeaderName, LPCSTR lpszHeaderValue, LPCTSTR lpszName = nullptr);
void PostOnHeadersComplete(CONNID dwConnID, LPCSTR lpszSummary, LPCTSTR lpszName = nullptr);
void PostOnBody(CONNID dwConnID, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
void PostOnChunkHeader(CONNID dwConnID, int iLength, LPCTSTR lpszName = nullptr);
void PostOnChunkComplete(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostOnMessageComplete(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostOnUpgrade(CONNID dwConnID, EnHttpUpgradeType enUpgradeType, LPCTSTR lpszName = nullptr);
void PostOnParseError(CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc, LPCTSTR lpszName = nullptr);
void PostOnWSMessageHeader(CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen, LPCTSTR lpszName = nullptr);
void PostOnWSMessageBody(CONNID dwConnID, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
void PostOnWSMessageComplete(CONNID dwConnID, LPCTSTR lpszName = nullptr);
void PostUncompressBody(CONNID dwConnID, int iLength, LPCTSTR lpszName = nullptr);
void PostUncompressBodyFail(CONNID dwConnID, int iResult, LPCTSTR lpszName = nullptr);
void PostInfoMsg(info_msg* msg);
void LogInfoMsg(info_msg* pInfoMsg);
void LogMsg(const CString& msg);
extern LPCTSTR g_lpszDefaultCookieFile;
LPCTSTR GetDefaultCookieFile();
#ifdef _SSL_SUPPORT
extern int g_c_iVerifyMode;
extern BOOL g_c_bNeedClientVerification;
extern LPCTSTR g_c_lpszCAPemCertFileOrPath;
extern LPCTSTR g_c_lpszPemCertFile;
extern LPCTSTR g_c_lpszPemKeyFile;
extern LPCTSTR g_c_lpszKeyPasswod;
extern int g_s_iVerifyMode;
extern BOOL g_s_bNeedClientVerification;
extern LPCTSTR g_s_lpszCAPemCertFileOrPath;
extern LPCTSTR g_s_lpszPemCertFile;
extern LPCTSTR g_s_lpszPemKeyFile;
extern LPCTSTR g_s_lpszKeyPasswod;
extern int g_c_iVerifyMode2;
extern BOOL g_c_bNeedClientVerification2;
extern LPCTSTR g_c_lpszCAPemCertFileOrPath2;
extern LPCTSTR g_c_lpszPemCertFile2;
extern LPCTSTR g_c_lpszPemKeyFile2;
extern LPCTSTR g_c_lpszKeyPasswod2;
extern int g_s_iVerifyMode2;
extern BOOL g_s_bNeedClientVerification2;
extern LPCTSTR g_s_lpszCAPemCertFileOrPath2;
extern LPCTSTR g_s_lpszPemCertFile2;
extern LPCTSTR g_s_lpszPemKeyFile2;
extern LPCTSTR g_s_lpszKeyPasswod2;
#endif
#ifdef _HTTP_SUPPORT
#include "../../src/common/crypto/crypto.h"
#define HTTP_NAME _T("http")
#define HTTPS_NAME _T("https")
#define CRLF "\r\n"
#define NV_SEPARATOR_CHAR '='
#define HEADER_SEPARATOR ": "
#define COOKIE_TOKENIZE "; "
#define STR_HTTP_1_0 "HTTP/1.0"
#define STR_HTTP_1_1 "HTTP/1.1"
#define HOST_HEADER "Host"
#define COOKIE_HEADER "Cookie"
#define SET_COOKIE_HEADER "Set-Cookie"
#define CONTENT_TYPE_HEADER "Content-Type"
#define CONTENT_LENGTH_HEADER "Content-Length"
#define TRANSFER_ENCODING_HEADER "Transfer-Encoding"
#define UPGRADE_HEADER "Upgrade"
#define WEB_SOCKET_HEADER_VALUE "WebSocket"
#define HTTP_METHOD_POST "POST"
#define HTTP_METHOD_PUT "PUT"
#define HTTP_METHOD_PATCH "PATCH"
#define HTTP_METHOD_GET "GET"
#define HTTP_METHOD_DELETE "DELETE"
#define HTTP_METHOD_HEAD "HEAD"
#define HTTP_METHOD_TRACE "TRACE"
#define HTTP_METHOD_OPTIONS "OPTIONS"
#define HTTP_METHOD_CONNECT "CONNECT"
#define HTTP_WEB_SOCKET_SEC_SALT "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
struct THttpHeader
{
CStringA strName;
CStringA strValue;
THttpHeader(LPCTSTR lpszName, LPCTSTR lpszValue) : strName(lpszName), strValue(lpszValue) {}
struct hash
{
size_t operator() (const CStringA& str) const
{
return hash_value(str);
}
};
struct equal_to
{
bool operator () (const CStringA& strA, const CStringA& strB) const
{
return strA == strB;
}
};
};
typedef unordered_multimap<CStringA, CStringA,
THttpHeader::hash, THttpHeader::equal_to> THttpHeaderMap;
typedef THttpHeaderMap::const_iterator THttpHeaderMapCI;
typedef THttpHeaderMap::iterator THttpHeaderMapI;
CStringA& HttpVersionToString(EnHttpVersion enVersion, CStringA& strResult);
CStringA& MakeSecWebSocketAccept(LPCSTR lpszKey, CStringA& strAccept);
#endif