-------------cpio.h
#pragma once
#include "SocketPool.h"
#include <list>
#include <afxmt.h>
#include "dll.h"
extern IOCP_API int g_running;
class IOCP_API CIOCP
{
public:
CIOCP(void);
virtual ~CIOCP(void);
public:
// 开始服务,port 为监听的TCP端口号,工作于TCP监听状态,其他方法请重写start方法
int Start(int port, int maxConnection);
// 停止服务
int Stop(void);
//处理IOCP上的消息
int ProcessIOCPMessage(ClientSocket* pClinetSocket, OVERLAPPEDEX* pOlex);
//工作线程处理逻辑
int WorkerThreadLogic(void);
//写数据
int WriteMessage(ClientSocket* pClinetSocket, BYTE* msg, int len,
const BOOL bSaveSend = TRUE);
//向一个UDP地址发送数据
int WriteMessageTo(ClientSocket* pClinetSocket, BYTE* msg, int len, sockaddr_in& addrTo,
const BOOL bSaveSend = TRUE);
//受到数据
virtual int RecvMessage(ClientSocket* pClinetSocket) = 0;
//新收到一个连接
virtual int NotifyNewConnect(ClientSocket* pClientSocket) = 0;
//断开一个连接
virtual int NotifyDisconnect(ClientSocket* pClientSocket) = 0;
//日志
virtual void Log(const char* msg,const LOG_PRINT__TYPE type = LOG_NOTIFY) = 0;
//处理完成端口上接受和发送udp消息的接口函数
virtual int ProcessUDPMessage(ClientSocket* pClientSock, OVERLAPPEDEX* pOLEX);
//收到UDP数据
virtual int RecvUDPMessage(ClientSocket* pClinetSocket) = 0;
//当accept缓冲区消耗完时,负责添加新的缓冲区
DWORD AcceptExThread();
//检查连接建立后是不是很长一短时间没有发送数据,如果是则断开连接
DWORD TcpLinkCheckthread();
public:
int m_iServerPort;
protected:
HANDLE m_hAcceptExThreadEvent; //tcp接收缓冲区消耗尽触发的事件
DWORD m_dwThreadCount;
HANDLE hCompletePort;
SOCKET m_listenSocket;
SOCKET m_udpSocket; //udp socket
SOCKET m_udpProxySocket; //udp 代理 socket
INT m_iMaxConnections;
CClientSocketPool m_clientSocketPool;
std::list<OVERLAPPEDEX*> m_lstOlePool; //重叠缓存池
std::list<OVERLAPPEDEX*> m_lstOlePoolAll; //重叠缓存池
CCriticalSection cs; //临界内存,保证多线程安全
public:
int CloseClientSock(ClientSocket* pClientSocket);
//2008-9-9 add
int AddTcpSocket( ClientSocket* pClientSock );
int AddUDPSocket(ClientSocket* pClientSock );
protected:
//初始化IOCP,创建ICOP句柄和开启工作线程
BOOL InitIocp(void);
};
------------------------------cpio.cpp
#include "afx.h"
#include "IOCP.h"
#include <algorithm>
#include <Objbase.h>
IOCP_API int g_running = FALSE;
DWORD WINAPI WorkerThreadFunc(LPVOID pParam);
DWORD WINAPI AcceptExThread(LPVOID pParam);
DWORD WINAPI TcpLinkCheckthread(LPVOID pParam);
//tcp保活时间结构体
struct tcp_keepalive {
u_long onoff;
u_long keepalivetime;
u_long keepaliveinterval;
};
// New WSAIoctl Options
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
#define SIO_RCVALL_MCAST _WSAIOW(IOC_VENDOR,2)
#define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3)
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
#define SIO_ABSORB_RTRALERT _WSAIOW(IOC_VENDOR,5)
#define SIO_UCAST_IF _WSAIOW(IOC_VENDOR,6)
#define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7)
#define SIO_INDEX_BIND _WSAIOW(IOC_VENDOR,8)
#define SIO_INDEX_MCASTIF _WSAIOW(IOC_VENDOR,9)
#define SIO_INDEX_ADD_MCAST _WSAIOW(IOC_VENDOR,10)
#define SIO_INDEX_DEL_MCAST _WSAIOW(IOC_VENDOR,11)
CIOCP::CIOCP(void)
{
hCompletePort = NULL;
m_listenSocket = INVALID_SOCKET;
m_udpSocket = INVALID_SOCKET;
m_udpProxySocket = INVALID_SOCKET;
m_iServerPort = 2000;
m_iMaxConnections = 20000;
m_dwThreadCount = 0;
m_hAcceptExThreadEvent = ::CreateEvent(NULL, TRUE, FALSE, _T("AcceptExThreadEvent") );
}
/***********************************************************************************************************/
//Function: ~CIOCP
//Notes: 释构函数,将内存池m_lstOlePool的资源释放
//
/***********************************************************************************************************/
CIOCP::~CIOCP(void)
{
//释放资源
cs.Lock(); //加锁
std::list<OVERLAPPEDEX*>::const_iterator itr = m_lstOlePoolAll.begin();
for (; itr != m_lstOlePoolAll.end(); ++itr)
{
delete *itr;
}
m_lstOlePoolAll.clear();
CloseHandle(m_hAcceptExThreadEvent);
cs.Unlock(); //解锁
if (hCompletePort != NULL)
{
Stop();
}
}
BOOL CIOCP::InitIocp()
{
m_dwThreadCount = 0;
//运行标志置1
InterlockedExchange((long *)&g_running, 1);
//创建完成端口
hCompletePort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
if ( 0 == hCompletePort)
{
Log("创建完成端口失败!");
return CREATE_COMPLETE_PORT_FAILURE;
}
SYSTEM_INFO systemInfo;
::GetSystemInfo(&systemInfo);
m_dwThreadCount = systemInfo.dwNumberOfProcessors * WORKER_THREAD_PER_CPU;
//创建Worker线程
for (DWORD i = 0; i < m_dwThreadCount; ++i)
{
HANDLE h = CreateThread(NULL,0,WorkerThreadFunc,this,0,NULL);
CloseHandle(h);
}
return 0;
}
// 开始服务
int CIOCP::Start(int port , int maxConnection)
{
m_iServerPort = port;
m_iMaxConnections = maxConnection;
//初始化IOCP
BOOL binit = InitIocp();
if (binit != 0)
{
return binit;
}
//获取主机地址
hostent* pHostEnt = gethostbyname("");
char* szIpAddr = inet_ntoa(*(struct in_addr *)*pHostEnt->h_addr_list);
int nServerip = inet_addr(szIpAddr);
//创建Listen Socket
m_listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( INVALID_SOCKET == m_listenSocket )
{
Log("创建监听端口失败!");
return CREATE_LISTEN_PORT_FAILURE;
}
CreateIoCompletionPort((HANDLE)m_listenSocket,hCompletePort,0,m_dwThreadCount);
//获取AcceptEx函数指针
GUID wsaidAcceptEx = WSAID_ACCEPTEX;
DWORD dwBytes = 0;
LPFN_ACCEPTEX m_lpfnAcceptEx;
WSAIoctl(m_listenSocket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&wsaidAcceptEx,
sizeof(wsaidAcceptEx),
&m_lpfnAcceptEx,
sizeof(m_lpfnAcceptEx),
&dwBytes,
NULL,
NULL);
//开始Listen
SOCKADDR_IN addr;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("0.0.0.0"); //htonl(INADDR_ANY);
addr.sin_port = htons(m_iServerPort);
bind(m_listenSocket,(PSOCKADDR)&addr,sizeof(addr));
int res = listen(m_listenSocket, 8);
//当tcp没有接收缓冲区的侍候,会触发此事件
if (m_hAcceptExThreadEvent)
{
::WSAEventSelect( m_listenSocket, m_hAcceptExThreadEvent, FD_ACCEPT );
HANDLE h = CreateThread(NULL, 0, ::AcceptExThread, this, 0, NULL);
CloseHandle(h);
}
HANDLE h = CreateThread(NULL, 0, ::TcpLinkCheckthread, this, 0, NULL);
CloseHandle(h);
//初始化ClientSocket池
Log("正在初始化Client Socket池,请稍候...");
m_clientSocketPool.Initialize(m_iMaxConnections, m_listenSocket, hCompletePort);
Log("服务器已经启动!");
return 0;
}
// 停止服务
int CIOCP::Stop(void)
{
InterlockedExchange((long *)&g_running, 0);
//关闭Socket池中的连接
Log("正在关闭Client Socket池,请稍候...");
m_clientSocketPool.Close();
//关闭Listen socket
closesocket(m_listenSocket);
m_listenSocket = INVALID_SOCKET;
//关闭udp socket
closesocket(m_udpSocket);
m_udpSocket = INVALID_SOCKET;
//关闭完成端口
if (hCompletePort != NULL)
{
CloseHandle(hCompletePort);
hCompletePort = NULL ;
}
Log("服务器停止!");
return 0;
}
int CIOCP::WorkerThreadLogic(void)
{
DWORD bytesTransferred;
ClientSocket* pClientSock;
OVERLAPPEDEX* pOLEX;
while (1 == InterlockedExchange((long *)&g_running, g_running))
{
pClientSock = NULL;
BOOL rtStatus = GetQueuedCompletionStatus(hCompletePort,
&bytesTransferred,
(LPDWORD) &pClientSock,
(LPOVERLAPPED*)&pOLEX,
INFINITE);
if ( 0 == InterlockedExchange((long *)&g_running, g_running))
{
break;
}
if ( FALSE == rtStatus )
{
DWORD errCode = GetLastError();
if ( ERROR_NETNAME_DELETED == errCode )
{
if (NULL == pClientSock && NULL != pOLEX)
{
Log("CloseClientSock");
m_clientSocketPool.ReleaseClientSock(pOLEX->pClientSock);
}
else
{
CloseClientSock(pClientSock);
}
}
else if(ERROR_OPERATION_ABORTED != errCode || WAIT_TIMEOUT != errCode )
{
Log("GetQueuedCompletionStatus 出错!");
}
continue;
}
//如果是udp连接
if ( pOLEX && pOLEX->pClientSock && pOLEX->pClientSock->bIsUPDSock)
{
pClientSock = pOLEX->pClientSock;
pClientSock->bytesTransferred = bytesTransferred;
BOOL bReadNextMessage = ProcessUDPMessage(pClientSock, pOLEX);
if (bReadNextMessage) //投递下一个数据接收
{
DWORD flag = MSG_PARTIAL;
DWORD ioSize = 0;
pClientSock->olex.ioType = READ;
//设置剩余缓冲区长度
pClientSock->olex.wsabuf.len = DATA_BUF_LENGHT -
((int)pClientSock->olex.wsabuf.buf - (int)pClientSock->olex.buf);
int rtSend = WSARecvFrom(
pClientSock->socket,
&pClientSock->olex.wsabuf,
1,
&pClientSock->bytesTransferred,
&flag,
(sockaddr*)pClientSock->AddressBuffer,
&pClientSock->iAddrLen,
(LPOVERLAPPED)&pClientSock->olex,
0);
}
}
else if( pOLEX && pOLEX->pClientSock)
{
pClientSock = pOLEX->pClientSock;
pClientSock->bytesTransferred = bytesTransferred;
int bReadNextMessage = TRUE;
try
{
bReadNextMessage = ProcessIOCPMessage(pClientSock, pOLEX);
}
catch (...)
{
Log("处理数据包异常!");
bReadNextMessage = TRUE;
}
//准备接受下一个数据包
if ( bReadNextMessage )
{
DWORD flag = MSG_PARTIAL;
DWORD ioSize = 0;
pClientSock->olex.ioType = READ;
//设置剩余缓冲区长度
pClientSock->olex.wsabuf.len = DATA_BUF_LENGHT -
((int)pClientSock->olex.wsabuf.buf - (int)pClientSock->olex.buf);
int rtSend = WSARecv(pClientSock->socket,
&pClientSock->olex.wsabuf,
1,
&pClientSock->bytesTransferred,
&flag,
(LPOVERLAPPED)&pClientSock->olex,
0);
if ( SOCKET_ERROR == rtSend &&
WSA_IO_PENDING != GetLastError())
{
//CloseClientSock(pClientSock);
}
}
}
}
return 0;
}
/***********************************************************************************************************/
//Function: ProcessIOCPMessage
//Notes: 处理完成端口上接受和发送数据的函数
//
//Input: pClientSock用户端口对象, pOLEX重叠缓冲区指针
/***********************************************************************************************************/
//处理IOCP上的消息
int CIOCP::ProcessIOCPMessage(ClientSocket* pClientSock, OVERLAPPEDEX* pOLEX)
{
//再上次操作中是否读了数据
BOOL bRecved = FALSE;
if (pOLEX && WRITE == pOLEX->ioType)
{
if (pOLEX->bSaveSend) //bSaveSend表示用安全重叠方式处理数据的发送,发送完后回收资源
{
cs.Lock();
m_lstOlePool.push_back(pOLEX);
cs.Unlock();
}
if (!pClientSock->bIsServer)
{
//CloseClientSock(pClientSock);
}
Log("已经发送完数据!/r/n");
bRecved = TRUE;
}
else
{
DWORD dwRet = 0;
switch(pClientSock->olex.ioType)
{
case ACCEPT:
setsockopt(pClientSock->socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
(char *)&m_listenSocket, sizeof (pClientSock->socket));
//设置保活时间为10秒,发送次数为2
//struct tcp_keepalive alive;
//alive.onoff = TRUE;
//alive.keepalivetime = 100000;
//alive.keepaliveinterval = 2;
//if (WSAIoctl(pClientSock->socket, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
// NULL, 0, &dwRet, NULL, NULL) == SOCKET_ERROR)
//{
// Log("WSAIotcl(SIO_KEEPALIVE_VALS) failed; %d/n");
//}
bRecved = NotifyNewConnect(pClientSock);
break;
case READ:
if( 0 == pClientSock->bytesTransferred)
{
CloseClientSock(pClientSock);
bRecved = TRUE;
}
else
bRecved = RecvMessage(pClientSock);
break;
case WRITE:
Log("已经发送完数据!");
bRecved = TRUE;
break;
default:
break;
}
}
return ! bRecved;
}
/***********************************************************************************************************/
//Function: WriteMessage
//Notes: 发送数据包到完成端口,如果是udp则采用udp方式,如果是tcp socket则采用tcp方式发送
//
//Input: ClientSocket* pClientSock 客户端口信息指针, BYTE* msg消息内容指针,int len数据长度,
// const BOOL bSaveSend是否采用安全的重叠方式发送
/***********************************************************************************************************/
int CIOCP::WriteMessage(ClientSocket* pClientSock, BYTE* msg, int len, const BOOL bSaveSend)
{
if (NULL == pClientSock || NULL == msg)
{
Log("套接字非法");
return 0;
}
if (pClientSock->bIsUPDSock) //如果是UPD socket,则采用UDP的方式发送
{
int addrlen = sizeof(sockaddr_in);
int errCode = sendto(pClientSock->socket, (CHAR*)msg, len, 0,
(sockaddr*)pClientSock->AddressBuffer, addrlen);
if (errCode == SOCKET_ERROR)
{
errCode = GetLastError();
}
return errCode;
}
else if (!bSaveSend)
{
send(pClientSock->socket,(CHAR*)msg, len, 0);
return 0;
}
else
{
if( len > DATA_BUF_LENGHT)
{
Log("发送的数据过长");
return 0;
}
OVERLAPPEDEX* pOlex = NULL;
//上锁
cs.Lock();
if (m_lstOlePool.empty()) //没有可用资源则new
{
pOlex = new OVERLAPPEDEX;
m_lstOlePoolAll.push_back(pOlex);
if (m_lstOlePoolAll.size() > 10000)//防止快速过量申请缓存
{
Sleep(m_lstOlePoolAll.size()/10000);
}
}
else //从缓冲池中分配
{
pOlex = *m_lstOlePool.begin();
m_lstOlePool.pop_front();
}
cs.Unlock(); //解锁
*pOlex = pClientSock->olex;
pOlex->bSaveSend = TRUE;
memcpy(&(pOlex->buf), msg, len);
pOlex->ioType = WRITE;
pOlex->wsabuf.len = len;
pOlex->wsabuf.buf = (CHAR*)&(pOlex->buf);
pOlex->bytesTransferred = len;
//发送数据到客户端
DWORD flag = MSG_PARTIAL;
int rtSend = WSASend(pClientSock->socket,
&pOlex->wsabuf,
1,
&(pOlex->bytesTransferred),
flag,
(LPOVERLAPPED)pOlex,
0);
if ( SOCKET_ERROR == rtSend &&
WSA_IO_PENDING != GetLastError())
{
delete pOlex;
CloseClientSock(pClientSock);
}
}
return 0;
}
/***********************************************************************************************************/
//Function: WriteMessage
//Notes: 向一个UDP地址发送数据
//
//Input: ClientSocket* pClientSock 客户端口信息指针, BYTE* msg消息内容指针,int len数据长度,
// const BOOL bSaveSend是否采用安全的重叠方式发送
/***********************************************************************************************************/
int CIOCP::WriteMessageTo(ClientSocket* pClinetSocket, BYTE* msg, int len, sockaddr_in& addrTo,
const BOOL bSaveSend)
{
//如果不是udp数据的套接字,则报错
if (!pClinetSocket->bIsUPDSock)
{
Log("WriteMessageTo 只能发送udp数据包!");
return 0;
}
if (bSaveSend) //使用阻塞的方式发送
{
int addrlen = sizeof(sockaddr_in);
int errCode = sendto(m_udpProxySocket, (CHAR*)msg, len, 0,
(sockaddr*)&addrTo, addrlen);
if (errCode == SOCKET_ERROR)
{
errCode = GetLastError();
}
}
{
if( len > DATA_BUF_LENGHT)
{
Log("发送的数据过长");
return 0;
}
OVERLAPPEDEX* pOlex = NULL;
//上锁
cs.Lock();
if (m_lstOlePool.empty()) //没有可用资源则new
{
pOlex = new OVERLAPPEDEX;
m_lstOlePoolAll.push_back(pOlex);
if (m_lstOlePoolAll.size() >= 100)
{
m_lstOlePool.insert(m_lstOlePool.end() ,m_lstOlePoolAll.begin() ,m_lstOlePoolAll.end());
}
}
else //从缓冲池中分配
{
pOlex = *m_lstOlePool.begin();
m_lstOlePool.pop_front();
}
cs.Unlock(); //解锁
*pOlex = pClinetSocket->olex;
pOlex->bSaveSend = TRUE;
memcpy(&(pOlex->buf), msg, len);
pOlex->ioType = WRITE;
pOlex->wsabuf.len = len;
pOlex->wsabuf.buf = (CHAR*)&(pOlex->buf);
pOlex->bytesTransferred = len;
int addrlen = sizeof(sockaddr_in);
//发送数据到客户端
DWORD flag = 0;//MSG_WAITALL;
int rtSend = WSASendTo(pClinetSocket->socket,
&pOlex->wsabuf,
1,
&(pOlex->bytesTransferred ),
flag,
(sockaddr*)&addrTo,
addrlen,
(LPOVERLAPPED)pOlex,
0);
}
return 0;
}
//线程函数入口
DWORD WINAPI WorkerThreadFunc(LPVOID pParam)
{
// ::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);
((CIOCP*)pParam)->WorkerThreadLogic();
return 0;
}
int CIOCP::CloseClientSock( ClientSocket* pClientSocket )
{
if (pClientSocket && !pClientSocket->bIsUPDSock) //如果是tcp连接
{
m_clientSocketPool.ReleaseClientSock(pClientSocket);
NotifyDisconnect(pClientSocket);
}
return 0;
}
/***********************************************************************************************************/
//Function: ProcessUDPMessage
//Notes: 处理完成端口上UDP接受和发送数据的函数
//
//Input: pClientSock用户端口对象, pOLEX重叠缓冲区指针
/***********************************************************************************************************/
//处理IOCP上的消息
int CIOCP::ProcessUDPMessage(ClientSocket* pClientSock, OVERLAPPEDEX* pOLEX)
{
//再上次操作中是否读完了数据
BOOL bRecved = FALSE;
if (pOLEX && WRITE == pOLEX->ioType)
{
if (pOLEX->bSaveSend) //bSaveSend表示用安全重叠方式处理数据的发送,发送完后回收资源
{
cs.Lock();
m_lstOlePool.push_back(pOLEX);
cs.Unlock();
}
Log("已经发送完数据!");
bRecved = TRUE;
}
else
{
switch(pClientSock->olex.ioType)
{
case READ:
bRecved = RecvUDPMessage(pClientSock);
break;
case WRITE:
Log("已经发送完UDP数据!");
bRecved = TRUE;
break;
default:
break;
}
}
return !bRecved;
}
//增加一个TCP连接,并投递一个读操作
int CIOCP::AddTcpSocket( ClientSocket* pClientSock )
{
if ( pClientSock )
{
// if (pClientSock->bIsServer)
// {
// clientSocketPool.SettingClientSocket(pClientSock);
//}
// else
//{
//关联完成端口
CreateIoCompletionPort((HANDLE)pClientSock->socket, hCompletePort, (DWORD)pClientSock, 0);
//异步等待Socket连接
memset( &(pClientSock->olex) , 0, sizeof(OVERLAPPEDEX));
pClientSock->bIsUPDSock = FALSE; //设置UDP连接标志
pClientSock->olex.pClientSock = pClientSock;
pClientSock->bytesTransferred = 0;
DWORD flag = MSG_PARTIAL;
DWORD ioSize = 0;
pClientSock->olex.ioType = READ;
//设置剩余缓冲区长度
pClientSock->olex.wsabuf.buf = pClientSock->olex.buf;
pClientSock->olex.wsabuf.len = DATA_BUF_LENGHT;
int rtSend = WSARecv(pClientSock->socket,
&pClientSock->olex.wsabuf,
1,
&pClientSock->bytesTransferred,
&flag,
(LPOVERLAPPED)&pClientSock->olex,
0);
if ( SOCKET_ERROR == rtSend &&
WSA_IO_PENDING != GetLastError())
{
return FALSE;
//CloseClientSock(pClientSock);
}
//}
}
else
{
return FALSE;
}
return TRUE;
}
int CIOCP::AddUDPSocket( ClientSocket* pClientSock)
{
int res = 0;
if ( pClientSock )
{
SOCKET socket = pClientSock->socket;
//关联完成端口
CreateIoCompletionPort((HANDLE)pClientSock->socket, hCompletePort,(DWORD)pClientSock, 0);
//准备接受数据包
//异步等待Socket连接
memset( &(pClientSock->olex) , 0, sizeof(OVERLAPPEDEX));
pClientSock->olex.pClientSock = pClientSock;
pClientSock->olex.wsabuf.buf = pClientSock->olex.buf;
pClientSock->bytesTransferred = 0;
pClientSock->bIsUPDSock = TRUE; //设置UDP连接标志
pClientSock->iAddrLen = sizeof(sockaddr_in);
DWORD flag = MSG_PARTIAL;
DWORD ioSize = 0;
pClientSock->olex.ioType = READ;
pClientSock->olex.wsabuf.len = DATA_BUF_LENGHT;
int rtSend = WSARecvFrom(
pClientSock->socket,
&pClientSock->olex.wsabuf,
1,
&pClientSock->bytesTransferred,
&flag,
(sockaddr*)pClientSock->AddressBuffer,
&pClientSock->iAddrLen,
(LPOVERLAPPED)&pClientSock->olex,
0);
res = GetLastError();
if ( SOCKET_ERROR == rtSend &&
WSA_IO_PENDING != GetLastError())
{
closesocket(pClientSock->socket);
return FALSE;
}
pClientSock = NULL;
}
return TRUE;
}
/***********************************************************************************************************/
//Function: AcceptExThread
//Notes: 处理完成端口上UDP接受和发送数据的函数
/***********************************************************************************************************/
DWORD CIOCP::AcceptExThread()
{
// 负责保证有足够多的 AcceptEx 可以接受连接请求的线程
while (1 == InterlockedExchange((long *)&g_running, g_running))
{
DWORD dwRes = ::WaitForSingleObject( m_hAcceptExThreadEvent, INFINITE );
if( dwRes == WAIT_FAILED )
{
break;
}
::ResetEvent( m_hAcceptExThreadEvent );
//当资源不够时,每次增加10个
m_clientSocketPool.AddTCPAcceptBuff(10);
}
return 0;
}
/***********************************************************************************************************/
//Function: AcceptExThread
//Notes: /线程函数入口
//
/***********************************************************************************************************/
DWORD WINAPI AcceptExThread(LPVOID pParam)
{
if (pParam)
{
((CIOCP*)pParam)->AcceptExThread();
}
return 0;
}
/***********************************************************************************************************/
//Function: TcpLinkCheckthread
//Notes: /线程函数入口
//
/***********************************************************************************************************/
DWORD WINAPI TcpLinkCheckthread(LPVOID pParam)
{
if (pParam)
{
((CIOCP*)pParam)->AcceptExThread();
}
return 0;
}
/***********************************************************************************************************/
//Function: TcpLinkCheckthread
//Notes: 检查tcp连接是不是建立后没有发送数据,如果建立连接后5分钟不发送数据则自动断开
/***********************************************************************************************************/
DWORD CIOCP::TcpLinkCheckthread()
{
//下面方法还不能防止攻击,暂时屏蔽
return 0;
// 负责保证有足够多的 AcceptEx 可以接受连接请求的线程
std::list<ClientSocket*> clientSocketList;
int iSecs = 0;
int iBytes = sizeof( int );
while (1 == InterlockedExchange((long *)&g_running, g_running))
{
//获取所有的连接缓冲区
m_clientSocketPool.GetTcpClientSock(clientSocketList);
std::list<ClientSocket*>::iterator itr = clientSocketList.begin();
for (; itr != clientSocketList.end(); ++itr)
{
if (*itr)
{
iSecs = 0;
getsockopt((*itr)->socket, SOL_SOCKET, SO_CONNECT_TIME, (char *)&iSecs, &iBytes );
//避免一个连接占用时间过长
if (iSecs > 6000000)
{
CloseClientSock(*itr);
}
}
}
//没5分钟检查一次
Sleep(300000);
}
return 0;
}