IOCP代码瘫痪有关问题
求助:IOCP代码瘫痪问题?
我写了一个IOCP,当我在单机测试,本机即充当服务器,又充当客户端。客户端模拟上传文件,模拟方法是,每次上传8000字节到服务器,服务器反馈一个41字节的信息给客户端。客户端收到信息后,继续发送8000字节,循环4000次。这就是一次上传过程。当连续模拟5-6次后,上传流量开始减少,最后,服务器SafeArrayCreateVector失败,甚至连字符串分配、组件对象创建创建都返回空导致内存异常而崩溃。
可是,当我将客户端和服务器在不同机器上运行,客户端上传或下载数据,客户端和服务器比较稳定。我想问的问题是,是不是ICOP本身的缺陷导致的这个问题,还是我的代码问题导致的该问题。给分100分,请各位专家解答!
我的IOCP基本思路如下:
1)定义PER_IO_OPERATION_DATA和_PER_HANDLE_DATA
我写了一个IOCP,当我在单机测试,本机即充当服务器,又充当客户端。客户端模拟上传文件,模拟方法是,每次上传8000字节到服务器,服务器反馈一个41字节的信息给客户端。客户端收到信息后,继续发送8000字节,循环4000次。这就是一次上传过程。当连续模拟5-6次后,上传流量开始减少,最后,服务器SafeArrayCreateVector失败,甚至连字符串分配、组件对象创建创建都返回空导致内存异常而崩溃。
可是,当我将客户端和服务器在不同机器上运行,客户端上传或下载数据,客户端和服务器比较稳定。我想问的问题是,是不是ICOP本身的缺陷导致的这个问题,还是我的代码问题导致的该问题。给分100分,请各位专家解答!
我的IOCP基本思路如下:
1)定义PER_IO_OPERATION_DATA和_PER_HANDLE_DATA
- C/C++ code
typedef struct { OVERLAPPED Overlapped; WSABUF DataBuf; char Buffer[MAX_BUFFER_SIZE]; BYTE operType; DWORD BytesRecv; DWORD BytesLength; DWORD BytesPin; DWORD BytesFrom; }PER_IO_OPERATION_DATA,*LPPER_IO_OPERATION_DATA; typedef struct _PER_HANDLE_DATA { SOCKET Socket; SOCKADDR_IN addressinfo; char parameters[256]; HANDLE g_pUser; HANDLE g_pServer; DOUBLE RecentTime; LPPER_IO_OPERATION_DATA PerIoData;//服务器每个客户链接的WSARecv对应的PerIoData LPPER_IO_OPERATION_DATA wPerIoData;//服务器每个客户链接的WSASend对应的PerIoData }PER_HANDLE_DATA,*LPPER_HANDLE_DATA; 2)ProcessIO关键代码: UINT WINAPI CServerSocket::ProcessIO(LPVOID lpParam) { ::CoInitializeEx(NULL,COINIT_MULTITHREADED); .... while(true) { if(0 == GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,(PULONG_PTR)&PerHandleData,(LPOVERLAPPED*)&lpOverlapped,INFINITE)) { if( (GetLastError() == WAIT_TIMEOUT) || (GetLastError() == ERROR_NETNAME_DELETED) ) { PerIoData = (LPPER_IO_OPERATION_DATA)CONTAINING_RECORD(lpOverlapped,PER_IO_OPERATION_DATA,Overlapped); if(PerHandleData==NULL) { ::GlobalFree(PerIoData); SetEvent(m_Tread); return 0; } IsOk=VARIANT_FALSE; if(PerHandleData->g_pUser!=NULL) { m_pServer->Fire_OnClientQuit((INetUser*)PerHandleData->g_pUser); CNetUsers*cUsers=(CNetUsers*)m_pServer->pUsers; cUsers->RemoveUser((INetUser*)PerHandleData->g_pUser,&IsOk); PerHandleData=NULL; } continue; } } PerIoData = (LPPER_IO_OPERATION_DATA)CONTAINING_RECORD(lpOverlapped,PER_IO_OPERATION_DATA,Overlapped); if(PerHandleData==NULL) { ::GlobalFree(PerIoData); SetEvent(m_Tread); ::CoUninitialize(); return 0; } // 说明客户端已经退出 if((BytesTransferred == 0)&&(PerIoData->operType==0)) { IsOk=VARIANT_FALSE; if(PerHandleData->g_pUser!=NULL) { CNetUsers*cUsers=(CNetUsers*)m_pServer->pUsers; m_pServer->Fire_OnClientQuit((INetUser*)PerHandleData->g_pUser); cUsers->RemoveUser((INetUser*)PerHandleData->g_pUser,&IsOk); } continue; } if(PerIoData->operType==0) { PerIoData->BytesRecv+=BytesTransferred; if(PerIoData->BytesLength==0) { if(PerIoData->BytesRecv<8) { ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED)); PerIoData->BytesPin+=BytesTransferred; PerIoData->DataBuf.buf = PerIoData->Buffer+PerIoData->BytesPin; PerIoData->DataBuf.len = MAX_BUFFER_SIZE-PerIoData->BytesPin; WSARecv(PerHandleData->Socket, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL); continue; } char*buffer=(char*)PerIoData->Buffer+PerIoData->BytesFrom; //操作同一块内存区域 LONG BufferSize; char*ca=(char*)&BufferSize; memcpy(ca,buffer+4,4); PerIoData->BytesLength=BufferSize+PACKAGE_HEADER; } bool IsValid=true; if(PerIoData->BytesRecv>=PerIoData->BytesLength) { int ValidPin=PerIoData->BytesPin+BytesTransferred; while(TRUE) { char*buffer=(char*)PerIoData->Buffer+PerIoData->BytesFrom; //操作同一块内存区域 LONG BufferSize; char*ca=(char*)&BufferSize; memcpy(ca,buffer+4,4); BufferSize+=PACKAGE_HEADER; if(PerIoData->BytesFrom+BufferSize>ValidPin) { for(int k=PerIoData->BytesFrom;k<ValidPin;k++) { PerIoData->Buffer[k-PerIoData->BytesFrom]=PerIoData->Buffer[k]; } PerIoData->BytesLength=BufferSize; PerIoData->BytesRecv=ValidPin-PerIoData->BytesFrom; PerIoData->BytesPin=PerIoData->BytesRecv; PerIoData->BytesFrom=0; break; } IDataPackage*pdr; CDataPackage::_CreatorClass::CreateInstance(NULL, __uuidof(IDataPackage), (void**)&pdr); BYTE*data=new BYTE[BufferSize]; if(data!=NULL) { memcpy(data,buffer,BufferSize); CDataPackage*cPack=(CDataPackage*)pdr; cPack->buffer=data; IsValid=m_pServer->NotifyAcceptDataPackage(PerHandleData,pdr); if(!IsValid) { pdr->Release(); break; } } pdr->Release(); PerIoData->BytesFrom+=BufferSize; BufferSize=PerIoData->BytesPin+BytesTransferred-PerIoData->BytesFrom; if(BufferSize<PACKAGE_HEADER) { for(int k=0;k<BufferSize;k++) { PerIoData->Buffer[k]=PerIoData->Buffer[PerIoData->BytesFrom+k]; } PerIoData->BytesLength=0; PerIoData->BytesRecv=BufferSize; PerIoData->BytesPin=BufferSize; PerIoData->BytesFrom=0; break; } } } else { PerIoData->BytesPin+=BytesTransferred; } if(!IsValid) continue; // 取得数据并处理 // 继续向 socket 投递WSARecv操作 ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.buf = PerIoData->Buffer+PerIoData->BytesPin; PerIoData->DataBuf.len = MAX_BUFFER_SIZE-PerIoData->BytesPin; WSARecv(PerHandleData->Socket, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL); } else if(PerIoData->operType==1) { m_pServer->sis.NotifyOutBytes(BytesTransferred); if(PerHandleData->g_pServer==m_pServer) { if(BytesTransferred+PerIoData->BytesFrom<PerIoData->BytesLength) { ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.buf=PerIoData->Buffer+BytesTransferred+PerIoData->BytesFrom; PerIoData->DataBuf.len=PerIoData->BytesLength-(BytesTransferred+PerIoData->BytesFrom); PerIoData->BytesLength-=BytesTransferred; PerIoData->BytesFrom+=BytesTransferred; DWORD SendBytes; WSASend(PerHandleData->Socket,&(PerIoData->DataBuf),1,&SendBytes,0,&(PerIoData->Overlapped),NULL); } else if(BytesTransferred>0) { INetUser*pUser=(INetUser*)PerHandleData->g_pUser; CNetUser*cUser=(CNetUser*)pUser; cUser->SendNextPackage(); } } } } SetEvent(m_Tread); ::CoUninitialize(); return 0; }