#ifndef _IOCP_MANAGER_H_
#define _IOCP_MANAGER_H_
#include <atlcoll.h>
#define DATA_BUFSIZE 8192 // 把数据缓冲区定义为8K是一个比较被Microsoft推荐的大小
#define WAIT_TIME_FOR_THREAD 5000 //等待线程结束的超时值
//单句柄数据
typedef struct _SPerIOHandle
{
SOCKET m_hSocket; //保存套接字句柄
static _SPerIOHandle* AllocPerIOHandle( SOCKET hSocket )
{
_SPerIOHandle* pPerIOHandle = (_SPerIOHandle*)::GlobalAlloc( GPTR, sizeof( _SPerIOHandle ));
if( pPerIOHandle != NULL )
{
pPerIOHandle->m_hSocket = hSocket;
}
return pPerIOHandle;
}
static void FreePerIOHandle( _SPerIOHandle* pPerIOHandle )
{
::GlobalFree( pPerIOHandle );
}
}SPerIOHandle, *PSPerIOHandle;
//投送操作类型
enum EOperation
{
IO_ACCEPT,
IO_WRITE,
IO_READ
};
//投送操作数据
typedef struct _SPerIOData
{
OVERLAPPED m_overlapped; //重叠结构
WSABUF m_wsaDataBuf;
CHAR m_szBuffer[DATA_BUFSIZE]; //投送操作的数据缓冲区
SOCKET m_hAcceptSocket; //用于Accept投放操作,保存连接的套接字句柄
EOperation m_oprType; //投送类型
static _SPerIOData* AllocPerIOData( EOperation oprType )
{
_SPerIOData* pPerIOData = (_SPerIOData*)::GlobalAlloc( GPTR, sizeof( _SPerIOData ));
if( pPerIOData != NULL )
{
pPerIOData->m_oprType = oprType;
//使用AcceptEx函数需要事先创建连接套件字
pPerIOData->m_hAcceptSocket = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED); ;
pPerIOData->m_overlapped.Internal = 0;
pPerIOData->m_overlapped.InternalHigh = 0;
pPerIOData->m_overlapped.Offset = 0;
pPerIOData->m_overlapped.OffsetHigh = 0;
pPerIOData->m_overlapped.hEvent = NULL;
pPerIOData->m_wsaDataBuf.buf = pPerIOData->m_szBuffer;
pPerIOData->m_wsaDataBuf.len = sizeof( pPerIOData->m_szBuffer );
ZeroMemory( pPerIOData->m_wsaDataBuf.buf, pPerIOData->m_wsaDataBuf.len );
}
return pPerIOData;
}
static void FreePerIOData( _SPerIOData* pPerIOData )
{
::GlobalFree( pPerIOData );
}
}SPerIOData, *PSPerIOData;
/*
* IOCP管理员
*/
class CIOCPManager
{
private:
HANDLE m_hCompletePort; //完成端口句柄
CAtlArray<HANDLE> m_arrOprThread; //保存工作线程句柄
CAtlArray<HANDLE> m_arrAcceptThread; //保存接受连接的线程句柄
//接受连接线程处理函数
static DWORD WINAPI sAcceptThread( LPVOID lpParameter );
//工作线程处理函数
static DWORD WINAPI sWorkThread( LPVOID lpParameter );
protected:
/* 处理Accept投送结果
* pPerIOHandle: 保存单句柄数据
* pPerIOData: 保存投送数据
* bRelease参数指示在处理函数中是否释放I/O重叠结构
*/
virtual int HandleAccept( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease );
//处理Recv投送结果
virtual int HandleRecvData( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease );
//处理Send投送结果
virtual int HandleSendData( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease );
public:
CIOCPManager();
/*创建完成端口管理
* nThreadCount: 指定工作线程的数目,为0时默认指定为: CPU个数 * 2
*/
BOOL Create( int nThreadCount = 0 );
//销毁完成端口管理
BOOL Destroy();
/* 开启接收连接操作
* hSocket:指定套接字,以便在其上进行Accept操作
*/
BOOL StartAccept( SOCKET hSocket );
/*
* 绑定套接字到完成端口上
*/
BOOL AssociateSocketToIOCP( SOCKET hSocket );
};
#endif
IOCPManager.cpp文件:
#define _IOCP_MANAGER_H_
#include <atlcoll.h>
#define DATA_BUFSIZE 8192 // 把数据缓冲区定义为8K是一个比较被Microsoft推荐的大小
#define WAIT_TIME_FOR_THREAD 5000 //等待线程结束的超时值
//单句柄数据
typedef struct _SPerIOHandle
{
SOCKET m_hSocket; //保存套接字句柄
static _SPerIOHandle* AllocPerIOHandle( SOCKET hSocket )
{
_SPerIOHandle* pPerIOHandle = (_SPerIOHandle*)::GlobalAlloc( GPTR, sizeof( _SPerIOHandle ));
if( pPerIOHandle != NULL )
{
pPerIOHandle->m_hSocket = hSocket;
}
return pPerIOHandle;
}
static void FreePerIOHandle( _SPerIOHandle* pPerIOHandle )
{
::GlobalFree( pPerIOHandle );
}
}SPerIOHandle, *PSPerIOHandle;
//投送操作类型
enum EOperation
{
IO_ACCEPT,
IO_WRITE,
IO_READ
};
//投送操作数据
typedef struct _SPerIOData
{
OVERLAPPED m_overlapped; //重叠结构
WSABUF m_wsaDataBuf;
CHAR m_szBuffer[DATA_BUFSIZE]; //投送操作的数据缓冲区
SOCKET m_hAcceptSocket; //用于Accept投放操作,保存连接的套接字句柄
EOperation m_oprType; //投送类型
static _SPerIOData* AllocPerIOData( EOperation oprType )
{
_SPerIOData* pPerIOData = (_SPerIOData*)::GlobalAlloc( GPTR, sizeof( _SPerIOData ));
if( pPerIOData != NULL )
{
pPerIOData->m_oprType = oprType;
//使用AcceptEx函数需要事先创建连接套件字
pPerIOData->m_hAcceptSocket = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED); ;
pPerIOData->m_overlapped.Internal = 0;
pPerIOData->m_overlapped.InternalHigh = 0;
pPerIOData->m_overlapped.Offset = 0;
pPerIOData->m_overlapped.OffsetHigh = 0;
pPerIOData->m_overlapped.hEvent = NULL;
pPerIOData->m_wsaDataBuf.buf = pPerIOData->m_szBuffer;
pPerIOData->m_wsaDataBuf.len = sizeof( pPerIOData->m_szBuffer );
ZeroMemory( pPerIOData->m_wsaDataBuf.buf, pPerIOData->m_wsaDataBuf.len );
}
return pPerIOData;
}
static void FreePerIOData( _SPerIOData* pPerIOData )
{
::GlobalFree( pPerIOData );
}
}SPerIOData, *PSPerIOData;
/*
* IOCP管理员
*/
class CIOCPManager
{
private:
HANDLE m_hCompletePort; //完成端口句柄
CAtlArray<HANDLE> m_arrOprThread; //保存工作线程句柄
CAtlArray<HANDLE> m_arrAcceptThread; //保存接受连接的线程句柄
//接受连接线程处理函数
static DWORD WINAPI sAcceptThread( LPVOID lpParameter );
//工作线程处理函数
static DWORD WINAPI sWorkThread( LPVOID lpParameter );
protected:
/* 处理Accept投送结果
* pPerIOHandle: 保存单句柄数据
* pPerIOData: 保存投送数据
* bRelease参数指示在处理函数中是否释放I/O重叠结构
*/
virtual int HandleAccept( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease );
//处理Recv投送结果
virtual int HandleRecvData( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease );
//处理Send投送结果
virtual int HandleSendData( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease );
public:
CIOCPManager();
/*创建完成端口管理
* nThreadCount: 指定工作线程的数目,为0时默认指定为: CPU个数 * 2
*/
BOOL Create( int nThreadCount = 0 );
//销毁完成端口管理
BOOL Destroy();
/* 开启接收连接操作
* hSocket:指定套接字,以便在其上进行Accept操作
*/
BOOL StartAccept( SOCKET hSocket );
/*
* 绑定套接字到完成端口上
*/
BOOL AssociateSocketToIOCP( SOCKET hSocket );
};
#endif
#include "stdafx.h"
#include "IOCPManager.h"
#include <Mswsock.h>
DWORD WINAPI CIOCPManager::sAcceptThread( LPVOID lpParameter )
{
SOCKET hSocket = (SOCKET)lpParameter;
DWORD dwRecvNumBytes = 0;
HANDLE hEvent = ::WSACreateEvent();
//利用EventSelect模型管理套接字的ACCEPT事件
int nRet = ::WSAEventSelect( hSocket, hEvent, FD_ACCEPT );
if ( nRet != 0 )
{
return -1;
}
while( TRUE )
{
::WSAWaitForMultipleEvents( 1, &hEvent, TRUE, WSA_INFINITE, FALSE );
::WSAResetEvent( hEvent );
PSPerIOData pPerIOData = SPerIOData::AllocPerIOData( IO_ACCEPT );
int nRet = ::AcceptEx( hSocket, pPerIOData->m_hAcceptSocket,
(LPVOID)( pPerIOData->m_szBuffer) ,
DATA_BUFSIZE - (2 * (sizeof(sockaddr_in ) + 16)),
sizeof(sockaddr_in ) + 16, sizeof(sockaddr_in ) + 16,
&dwRecvNumBytes,
(LPOVERLAPPED) &( pPerIOData->m_overlapped ));
if( nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError()) )
{
SPerIOData::FreePerIOData( pPerIOData );
}
}
return 0;
}
DWORD WINAPI CIOCPManager::sWorkThread( LPVOID lpParameter )
{
CIOCPManager *pIOCPMgr = (CIOCPManager*)lpParameter;
ATLASSERT( pIOCPMgr != NULL );
while ( TRUE )
{
DWORD dwTransferred(0);
PSPerIOHandle pPerIOHandle = NULL;
PSPerIOData pIOOperation = NULL;
BOOL bRet = ::GetQueuedCompletionStatus( pIOCPMgr->m_hCompletePort, &dwTransferred, (PULONG_PTR)&pPerIOHandle, (LPOVERLAPPED*)&pIOOperation, INFINITE );
if( !bRet )
{
DWORD dwError = ::GetLastError();
return 0;
}
//结束机制
if( pPerIOHandle == NULL )
return 0;
ATLASSERT( pPerIOHandle != NULL );
ATLASSERT( pIOOperation != NULL );
//socket退出
if( dwTransferred == 0 )
{
::closesocket( pPerIOHandle->m_hSocket );
SPerIOHandle::FreePerIOHandle( pPerIOHandle );
SPerIOData::FreePerIOData( pIOOperation );
continue;
}
BOOL bRelease = FALSE;
switch( pIOOperation->m_oprType )
{
case IO_ACCEPT:
{
pIOCPMgr->HandleAccept( pPerIOHandle, pIOOperation, bRelease );
}
break;
case IO_READ:
{
pIOCPMgr->HandleRecvData( pPerIOHandle, pIOOperation, bRelease );
}
break;
case IO_WRITE:
{
pIOCPMgr->HandleSendData( pPerIOHandle, pIOOperation, bRelease );
}
break;
}
if( !bRelease )
{
//释放 pIOOperation
SPerIOData::FreePerIOData( pIOOperation );
}
}
return 0;
}
CIOCPManager::CIOCPManager()
{
m_hCompletePort = NULL;
m_arrOprThread.RemoveAll();
m_arrAcceptThread.RemoveAll();
}
int CIOCPManager::HandleAccept( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease )
{
bRelease = TRUE; //由于需要循环使用PSPerIOData对象,在此将bRelease设为FALSE避免删除
ATLASSERT( pPerIOHandle != NULL );
ATLASSERT( pPerIOData != NULL );
//绑定到完成端口
if( !this->AssociateSocketToIOCP( pPerIOData->m_hAcceptSocket ) )
return -1;
//投递接收申请
pPerIOData->m_oprType = IO_READ;
ZeroMemory( pPerIOData->m_wsaDataBuf.buf, pPerIOData->m_wsaDataBuf.len );
DWORD dwIoSize = 0;
DWORD dwlFlags = MSG_PARTIAL;
::WSARecv( pPerIOData->m_hAcceptSocket, &pPerIOData->m_wsaDataBuf, 1, &dwIoSize, &dwlFlags, &pPerIOData->m_overlapped, NULL );
return 0;
}
int CIOCPManager::HandleRecvData( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease )
{
bRelease = TRUE;
ATLASSERT( pPerIOHandle != NULL );
ATLASSERT( pPerIOData != NULL );
//显示接收数据到输出窗口
CString strTrace;
strTrace.Format( _T("recv message: %s \n"), CA2T(pPerIOData->m_szBuffer) );
AtlTrace( strTrace );
//继续投递接收申请
ZeroMemory( pPerIOData->m_wsaDataBuf.buf, pPerIOData->m_wsaDataBuf.len );
DWORD dwIoSize = 0;
DWORD dwlFlags = 0;
::WSARecv( pPerIOData->m_hAcceptSocket, &pPerIOData->m_wsaDataBuf, 1, &dwIoSize, &dwlFlags, &pPerIOData->m_overlapped, NULL );
return 0;
}
int CIOCPManager::HandleSendData( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease )
{
bRelease = FALSE;
return 0;
}
BOOL CIOCPManager::Create( int nThreadCount )
{
if( nThreadCount == 0 )
{
//设置为0时,将线程设置为电脑CPU数 * 2
SYSTEM_INFO sysInfo;
::GetSystemInfo( &sysInfo );
nThreadCount = sysInfo.dwNumberOfProcessors * 2;
}
//创建完成端口
m_hCompletePort = ::CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, NULL, 0 );
ATLASSERT( m_hCompletePort != NULL );
if( m_hCompletePort == NULL )return FALSE;
//开启工作线程等待完成端口上的投放操作结果
m_arrOprThread.RemoveAll();
for ( int nIndex = 0; nIndex < nThreadCount; nIndex++ )
{
HANDLE hThread = ::CreateThread( NULL, 0, sWorkThread, (LPVOID)this, 0, NULL );
ATLASSERT( hThread != NULL );
m_arrOprThread.Add( hThread );
}
return TRUE;
}
BOOL CIOCPManager::Destroy()
{
//结束连接线程
int nAcceptThrCount = (int)m_arrAcceptThread.GetCount();
for ( int nIndex = 0; nIndex < nAcceptThrCount; nIndex++ )
{ //这里为简便,所以直接TerminateThread线程,有待完善
::TerminateThread( m_arrAcceptThread.GetAt( nIndex ), -1 );
::CloseHandle( m_arrAcceptThread.GetAt( nIndex ) );
}
m_arrAcceptThread.RemoveAll();
//结束工作线程
int nWorkThrCount = (int)m_arrOprThread.GetCount();
for ( int nIndex = 0; nIndex < nWorkThrCount; nIndex++ )
{ //投送结束线程通知(指定单句柄数据为NULL)
::PostQueuedCompletionStatus( m_hCompletePort, 0, NULL, NULL );
}
for ( int nIndex = 0; nIndex < nWorkThrCount; nIndex++ )
{
if( WAIT_TIMEOUT == ::WaitForSingleObject( m_arrOprThread.GetAt( nIndex ), WAIT_TIME_FOR_THREAD ) )
{
::TerminateThread( m_arrOprThread.GetAt( nIndex ), -1 );
}
::CloseHandle( m_arrOprThread.GetAt( nIndex ) );
}
m_arrOprThread.RemoveAll();
//删除完成端口对象
if( m_hCompletePort != NULL )
{
::CloseHandle( m_hCompletePort );
}
return TRUE;
}
BOOL CIOCPManager::StartAccept( SOCKET hSocket )
{
//关联套接字到完成端口
if( !this->AssociateSocketToIOCP( hSocket ) )
return FALSE;
//创建监听线程
HANDLE hThread = ::CreateThread( NULL, 0, sAcceptThread, (LPVOID)hSocket, 0, NULL );
ATLASSERT( hThread != NULL );
m_arrAcceptThread.Add( hThread );
return TRUE;
}
BOOL CIOCPManager::AssociateSocketToIOCP( SOCKET hSocket )
{
ATLASSERT( hSocket != NULL );
//分配单句柄数据
PSPerIOHandle pPerIOHandle = SPerIOHandle::AllocPerIOHandle( hSocket );
if( pPerIOHandle == NULL )
return FALSE;
m_hCompletePort = ::CreateIoCompletionPort( (HANDLE)hSocket, m_hCompletePort, (ULONG_PTR)pPerIOHandle, 0 );
ATLASSERT( m_hCompletePort != NULL );
if( m_hCompletePort == NULL )return FALSE;
return TRUE;
}
使用如:
#include "IOCPManager.h"
#include <Mswsock.h>
DWORD WINAPI CIOCPManager::sAcceptThread( LPVOID lpParameter )
{
SOCKET hSocket = (SOCKET)lpParameter;
DWORD dwRecvNumBytes = 0;
HANDLE hEvent = ::WSACreateEvent();
//利用EventSelect模型管理套接字的ACCEPT事件
int nRet = ::WSAEventSelect( hSocket, hEvent, FD_ACCEPT );
if ( nRet != 0 )
{
return -1;
}
while( TRUE )
{
::WSAWaitForMultipleEvents( 1, &hEvent, TRUE, WSA_INFINITE, FALSE );
::WSAResetEvent( hEvent );
PSPerIOData pPerIOData = SPerIOData::AllocPerIOData( IO_ACCEPT );
int nRet = ::AcceptEx( hSocket, pPerIOData->m_hAcceptSocket,
(LPVOID)( pPerIOData->m_szBuffer) ,
DATA_BUFSIZE - (2 * (sizeof(sockaddr_in ) + 16)),
sizeof(sockaddr_in ) + 16, sizeof(sockaddr_in ) + 16,
&dwRecvNumBytes,
(LPOVERLAPPED) &( pPerIOData->m_overlapped ));
if( nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError()) )
{
SPerIOData::FreePerIOData( pPerIOData );
}
}
return 0;
}
DWORD WINAPI CIOCPManager::sWorkThread( LPVOID lpParameter )
{
CIOCPManager *pIOCPMgr = (CIOCPManager*)lpParameter;
ATLASSERT( pIOCPMgr != NULL );
while ( TRUE )
{
DWORD dwTransferred(0);
PSPerIOHandle pPerIOHandle = NULL;
PSPerIOData pIOOperation = NULL;
BOOL bRet = ::GetQueuedCompletionStatus( pIOCPMgr->m_hCompletePort, &dwTransferred, (PULONG_PTR)&pPerIOHandle, (LPOVERLAPPED*)&pIOOperation, INFINITE );
if( !bRet )
{
DWORD dwError = ::GetLastError();
return 0;
}
//结束机制
if( pPerIOHandle == NULL )
return 0;
ATLASSERT( pPerIOHandle != NULL );
ATLASSERT( pIOOperation != NULL );
//socket退出
if( dwTransferred == 0 )
{
::closesocket( pPerIOHandle->m_hSocket );
SPerIOHandle::FreePerIOHandle( pPerIOHandle );
SPerIOData::FreePerIOData( pIOOperation );
continue;
}
BOOL bRelease = FALSE;
switch( pIOOperation->m_oprType )
{
case IO_ACCEPT:
{
pIOCPMgr->HandleAccept( pPerIOHandle, pIOOperation, bRelease );
}
break;
case IO_READ:
{
pIOCPMgr->HandleRecvData( pPerIOHandle, pIOOperation, bRelease );
}
break;
case IO_WRITE:
{
pIOCPMgr->HandleSendData( pPerIOHandle, pIOOperation, bRelease );
}
break;
}
if( !bRelease )
{
//释放 pIOOperation
SPerIOData::FreePerIOData( pIOOperation );
}
}
return 0;
}
CIOCPManager::CIOCPManager()
{
m_hCompletePort = NULL;
m_arrOprThread.RemoveAll();
m_arrAcceptThread.RemoveAll();
}
int CIOCPManager::HandleAccept( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease )
{
bRelease = TRUE; //由于需要循环使用PSPerIOData对象,在此将bRelease设为FALSE避免删除
ATLASSERT( pPerIOHandle != NULL );
ATLASSERT( pPerIOData != NULL );
//绑定到完成端口
if( !this->AssociateSocketToIOCP( pPerIOData->m_hAcceptSocket ) )
return -1;
//投递接收申请
pPerIOData->m_oprType = IO_READ;
ZeroMemory( pPerIOData->m_wsaDataBuf.buf, pPerIOData->m_wsaDataBuf.len );
DWORD dwIoSize = 0;
DWORD dwlFlags = MSG_PARTIAL;
::WSARecv( pPerIOData->m_hAcceptSocket, &pPerIOData->m_wsaDataBuf, 1, &dwIoSize, &dwlFlags, &pPerIOData->m_overlapped, NULL );
return 0;
}
int CIOCPManager::HandleRecvData( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease )
{
bRelease = TRUE;
ATLASSERT( pPerIOHandle != NULL );
ATLASSERT( pPerIOData != NULL );
//显示接收数据到输出窗口
CString strTrace;
strTrace.Format( _T("recv message: %s \n"), CA2T(pPerIOData->m_szBuffer) );
AtlTrace( strTrace );
//继续投递接收申请
ZeroMemory( pPerIOData->m_wsaDataBuf.buf, pPerIOData->m_wsaDataBuf.len );
DWORD dwIoSize = 0;
DWORD dwlFlags = 0;
::WSARecv( pPerIOData->m_hAcceptSocket, &pPerIOData->m_wsaDataBuf, 1, &dwIoSize, &dwlFlags, &pPerIOData->m_overlapped, NULL );
return 0;
}
int CIOCPManager::HandleSendData( PSPerIOHandle pPerIOHandle, PSPerIOData pPerIOData, BOOL& bRelease )
{
bRelease = FALSE;
return 0;
}
BOOL CIOCPManager::Create( int nThreadCount )
{
if( nThreadCount == 0 )
{
//设置为0时,将线程设置为电脑CPU数 * 2
SYSTEM_INFO sysInfo;
::GetSystemInfo( &sysInfo );
nThreadCount = sysInfo.dwNumberOfProcessors * 2;
}
//创建完成端口
m_hCompletePort = ::CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, NULL, 0 );
ATLASSERT( m_hCompletePort != NULL );
if( m_hCompletePort == NULL )return FALSE;
//开启工作线程等待完成端口上的投放操作结果
m_arrOprThread.RemoveAll();
for ( int nIndex = 0; nIndex < nThreadCount; nIndex++ )
{
HANDLE hThread = ::CreateThread( NULL, 0, sWorkThread, (LPVOID)this, 0, NULL );
ATLASSERT( hThread != NULL );
m_arrOprThread.Add( hThread );
}
return TRUE;
}
BOOL CIOCPManager::Destroy()
{
//结束连接线程
int nAcceptThrCount = (int)m_arrAcceptThread.GetCount();
for ( int nIndex = 0; nIndex < nAcceptThrCount; nIndex++ )
{ //这里为简便,所以直接TerminateThread线程,有待完善
::TerminateThread( m_arrAcceptThread.GetAt( nIndex ), -1 );
::CloseHandle( m_arrAcceptThread.GetAt( nIndex ) );
}
m_arrAcceptThread.RemoveAll();
//结束工作线程
int nWorkThrCount = (int)m_arrOprThread.GetCount();
for ( int nIndex = 0; nIndex < nWorkThrCount; nIndex++ )
{ //投送结束线程通知(指定单句柄数据为NULL)
::PostQueuedCompletionStatus( m_hCompletePort, 0, NULL, NULL );
}
for ( int nIndex = 0; nIndex < nWorkThrCount; nIndex++ )
{
if( WAIT_TIMEOUT == ::WaitForSingleObject( m_arrOprThread.GetAt( nIndex ), WAIT_TIME_FOR_THREAD ) )
{
::TerminateThread( m_arrOprThread.GetAt( nIndex ), -1 );
}
::CloseHandle( m_arrOprThread.GetAt( nIndex ) );
}
m_arrOprThread.RemoveAll();
//删除完成端口对象
if( m_hCompletePort != NULL )
{
::CloseHandle( m_hCompletePort );
}
return TRUE;
}
BOOL CIOCPManager::StartAccept( SOCKET hSocket )
{
//关联套接字到完成端口
if( !this->AssociateSocketToIOCP( hSocket ) )
return FALSE;
//创建监听线程
HANDLE hThread = ::CreateThread( NULL, 0, sAcceptThread, (LPVOID)hSocket, 0, NULL );
ATLASSERT( hThread != NULL );
m_arrAcceptThread.Add( hThread );
return TRUE;
}
BOOL CIOCPManager::AssociateSocketToIOCP( SOCKET hSocket )
{
ATLASSERT( hSocket != NULL );
//分配单句柄数据
PSPerIOHandle pPerIOHandle = SPerIOHandle::AllocPerIOHandle( hSocket );
if( pPerIOHandle == NULL )
return FALSE;
m_hCompletePort = ::CreateIoCompletionPort( (HANDLE)hSocket, m_hCompletePort, (ULONG_PTR)pPerIOHandle, 0 );
ATLASSERT( m_hCompletePort != NULL );
if( m_hCompletePort == NULL )return FALSE;
return TRUE;
}
SOCKET hSocket = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
if( hSocket == INVALID_SOCKET )
{
return 0;
}
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons((short) 5969 );
int nRetVal = bind( hSocket, (SOCKADDR *)&addr, sizeof(addr) );
if( nRetVal == SOCKET_ERROR )
return 0;
nRetVal = listen( hSocket, 10 );
if( nRetVal == SOCKET_ERROR )
return 0;
CIOCPManager iocpMgr;
iocpMgr.Create();
if( !iocpMgr.StartAccept( hSocket ) )
{
AtlMessageBox( NULL, _T("StartAccept Failed") );
}
Sleep( 100000 );
iocpMgr.Destroy();
if( hSocket == INVALID_SOCKET )
{
return 0;
}
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons((short) 5969 );
int nRetVal = bind( hSocket, (SOCKADDR *)&addr, sizeof(addr) );
if( nRetVal == SOCKET_ERROR )
return 0;
nRetVal = listen( hSocket, 10 );
if( nRetVal == SOCKET_ERROR )
return 0;
CIOCPManager iocpMgr;
iocpMgr.Create();
if( !iocpMgr.StartAccept( hSocket ) )
{
AtlMessageBox( NULL, _T("StartAccept Failed") );
}
Sleep( 100000 );
iocpMgr.Destroy();