能力值:
( LV2,RANK:10 )
|
-
-
2 楼
我记得IOCP关闭连接好像是用PostQueuedCompletionStatus发送消息 然后再处理此消息释放相应资源 而不是像你这样在管理者线程中直接closesocket.
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
多谢,我明天试试
|
能力值:
( LV2,RANK:10 )
|
-
-
4 楼
PostQueuedCompletionStatus会关闭线程,我仅仅是需要把此socket对应的资源释放掉。
|
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
把程序贴在这里吧,顺便说一下,通过日志我发现这个错误有个奇怪的现象,如果在“1111111”处成功close了n个socket,第一个和第n个不会引起“22222222”处的运行,即这两个socket对应的资源(PPER_IO_DATA , PPER_SOCKET_DATA)泄露了!
// 单I/O数据
typedef struct _IO_DATA
{
OVERLAPPED ol;
WSABUF DataBuf;
char Buffer[DEFAULT_BUFLEN];
MISC_HDR MiscHdr;
int LockFlag;
IO_TYPE IoType;
}PER_IO_DATA, *PPER_IO_DATA;
// 单句柄数据
typedef struct _SOCKET_DATA
{
SOCKET hSock;
SOCKADDR_IN ClientAddr;
bool ActiveFlag;
}PER_SOCKET_DATA, *PPER_SOCKET_DATA;
typedef vector<PPER_SOCKET_DATA> SocketDataVector;
typedef vector<PPER_IO_DATA> IoDataVector;
SocketDataVector gSockDataVec;
IoDataVector gIoDataVec;
//0----主线程
int _tmain( int argc, _TCHAR* argv[] )
{
//创建一个IO完成端口
hIocp = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 );
//初始化 Winsock.
iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
//创建一个监听套接字
ListenSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
//绑定端口至SPD_SERVER_LISTEN_PORT
iResult = bind( ListenSocket, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr) );
//监听
iResult = listen( ListenSocket, SOMAXCONN );
//创建工作线程
siSysInfo.dwNumberOfProcessors <<= 1;
for( int i=0; i < siSysInfo.dwNumberOfProcessors; i++ ) {
QueueUserWorkItem( WorkerThreadFunc, hIocp, WT_EXECUTELONGFUNCTION );
}
//创建连接管理线程
DWORD dwCMThreadId = 0;
HANDLE hCMThread = CreateThread(NULL, 0, ConnManagerThreadFunc,
NULL, 0, &dwCMThreadId);
//accept
SockLen = sizeof(ClientAddr);
while (true) {
SOCKET hAccept = accept(ListenSocket, (struct sockaddr *)&ClientAddr, &SockLen);
if(hAccept != INVALID_SOCKET) {
//分配单IO数据结构
PPER_IO_DATA pPerIoData = new PER_IO_DATA;
//分配单socket数据结构
PPER_SOCKET_DATA pPerHandleData = new PER_SOCKET_DATA;
pPerHandleData->hSock = hAccept;
memcpy(&pPerHandleData->ClientAddr, &ClientAddr, sizeof(ClientAddr));
pPerHandleData->ActiveFlag = true;
EnterCriticalSection(&csPerDataVec);
CreateIoCompletionPort( reinterpret_cast<HANDLE>(hAccept), hIocp,
reinterpret_cast<DWORD>(pPerHandleData), 0);
memset(pPerIoData, 0, sizeof(PER_IO_DATA));
pPerIoData->IoType = IoRecv;
pPerIoData->DataBuf.len = DEFAULT_BUFLEN;
pPerIoData->DataBuf.buf = pPerIoData->Buffer;
DWORD dwRecvd = 0;
DWORD dwFlags = 0;
WSARecv( hAccept, &pPerIoData->DataBuf, 1,
&dwRecvd, &dwFlags,
reinterpret_cast<LPWSAOVERLAPPED>(pPerIoData), NULL );
gSockDataVec.push_back(pPerHandleData);
gIoDataVec.push_back(pPerIoData);
LeaveCriticalSection(&csPerDataVec);
}
}
CloseHandle(hCMThread);
closesocket(ListenSocket);
WSACleanup();
CloseHandle(hIocp);
CloseLogFile(LogName);
return 0;
}
//1----工作者线程
DWORD WINAPI WorkerThreadFunc( LPVOID lpParam )
{
HANDLE hIocp = reinterpret_cast<HANDLE>( lpParam );
DWORD dwSend = 0;
DWORD dwRecvd = 0;
DWORD dwFlags = 0;
DWORD dwTransCount = 0;
PPER_IO_DATA pPerIoData = NULL;
PPER_SOCKET_DATA pPerHandleData = NULL;
int iResult = 0;
int nRetShutDown = -1;
int nRetClSockect = -1;
IoDataVector::iterator itrIoDelete;
while( TRUE ) {
if( GetQueuedCompletionStatus( hIocp, &dwTransCount,
reinterpret_cast<LPDWORD>(&pPerHandleData),
reinterpret_cast<LPOVERLAPPED*>(&pPerIoData), INFINITE ) )
{
if( dwTransCount == 0 && pPerIoData->IoType != IoQuit ) {
//客户端主动关闭连接
shutdown(pPerHandleData->hSock,SD_BOTH);
closesocket(pPerHandleData->hSock)!=0);
FreePerData(pPerIoData, pPerHandleData);
continue;
}
switch( pPerIoData->IoType ) {
case IoSend:
//一些处理
case IoRecv:
//另外一些处理
default:
;
}
}
else {//2222222222222222
//服务器已主动断开连接或客户端断开连接
if(pPerHandleData!=NULL&&pPerIoData!=NULL) {
FreePerData(pPerIoData, pPerHandleData);
}
}
}
LQUIT:
return 0;
}
//2----管理者线程
DWORD WINAPI ConnManagerThreadFunc( LPVOID lpParam )
{
while (true) {
EnterCriticalSection(&csPerDataVec); //这里需要加上互斥锁,否则工作线程对连接池进行修改会造成迭代器失效
SocketDataVector::iterator iter = gSockDataVec.begin();
for (; iter != gSockDataVec.end(); iter++)
{
//关闭该连接,这里不释放数据结构,工作线程会检测到断开连接并代为释放
shutdown((*iter)->hSock,SD_BOTH)!=0);
closesocket((*iter)->hSock)!=0);//11111111111111111111
}
LeaveCriticalSection(&csPerDataVec);
Sleep(SCAN_COON_INTERVAL);
}
return 0;
}
//3..释放单IO和单句柄数据结构
void FreePerData(PPER_IO_DATA pIoData, PPER_SOCKET_DATA pSocketData)
{
EnterCriticalSection( &csPerDataVec );
IoDataVector::iterator itrIoDelete = find( gIoDataVec.begin(), gIoDataVec.end(), pIoData );
SocketDataVector::iterator itrSockDelete = find( gSockDataVec.begin(), gSockDataVec.end(), pSocketData );
bool bFindIoData = itrIoDelete != gIoDataVec.end();
bool bFindSockData = itrSockDelete != gSockDataVec.end();
if ( bFindIoData&&bFindSockData) {
delete *itrIoDelete;
delete *itrSockDelete;
gIoDataVec.erase( itrIoDelete );
gSockDataVec.erase( itrSockDelete );
}
LeaveCriticalSection( &csPerDataVec );
}
|
能力值:
( LV5,RANK:70 )
|
-
-
6 楼
为什么要用外面的所谓“专家”新开发的库?boost.asio 现成的东西不用?说实话,boost.asio 是一套非常不错的库,至少比那些没经过考验的库好很多的!
|
能力值:
( LV5,RANK:70 )
|
-
-
7 楼
must try boost::asio
|
能力值:
( LV2,RANK:10 )
|
-
-
8 楼
标题吸引了我
|