求助:IOCP客户端下载数据服务器崩溃? 本帖最后由 VisualEleven 于 2012-05-26 10:32:04 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 代码发:[email protected]只看上面这些也不能判定是哪个地方出了问题。可能是其他地方 检查是不是线程同步问题举例就WSASend后SetEvent是有问题的由于WSASend是异步,此时不一定完成发送数据,最好将SetEvent放到GetQueuedCompletionStatus里PER_HANDLE_DATA里各自只有一个收发PER_IO_OPERATION_DATA,必然要做很多同步工作倒不如弄个收发队列,需要收发时,就申请一个新的PER_IO_OPERATION_DATA如果自己搞不定,上传代码,等大牛解决吧。 一般来说,malloc返回空,并不是因为内存耗尽,而是堆被破坏了.你应该首先从堆块越界上找原因。 我的代码是ATL代码,在我的IOCP的ProcessIO里面,我对PerIOData添加了是否越界的判断,没有找到越界的问题,还有就是SetEvent是保证包是按顺序发送的,即使是弄个收发队列,还是要使用SetEvent类似的方法的!会不会是组件对象不能跨线程呢,我的组件对象都是Both模型呀,支持多线程中的调用的! 这是我的ProcessIO源码:UINT WINAPI CServerSocket::ProcessIO(LPVOID lpParam){ ::CoInitializeEx(NULL,COINIT_MULTITHREADED); //::CoInitialize(NULL); ServerSocketStruct*ss=(ServerSocketStruct*)lpParam; CServerSocket*m_pServer=ss->m_pServer; HANDLE m_Tread=ss->m_Thread; delete ss; HANDLE CompletionPort = m_pServer->CompletionPort; DWORD BytesTransferred; LPPER_HANDLE_DATA PerHandleData; LPOVERLAPPED lpOverlapped; LPPER_IO_OPERATION_DATA PerIoData; DWORD Flags = 0; DWORD dwRecv = 0; VARIANT_BOOL IsOk; 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); ::CoUninitialize();#ifdef _DEBUG TRACE("接受线程退出\n");#endif 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();#ifdef _DEBUG TRACE("接受线程退出\n");#endif return 0; } // 说明客户端已经退出 if(BytesTransferred == 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->BytesSend==0) { m_pServer->sis.NotifyInBytes(BytesTransferred); CTime time=CTime::GetCurrentTime(); SYSTEMTIME systime; time.GetAsSystemTime(systime);//转成systime double dtime; SystemTimeToVariantTime(&systime,&dtime); PerHandleData->RecentTime=dtime; 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 { m_pServer->sis.NotifyOutBytes(BytesTransferred); if(PerHandleData->g_pServer==m_pServer) { if(BytesTransferred+PerIoData->BytesFrom<PerIoData->BytesSend) { ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.buf=PerIoData->Buffer+BytesTransferred+PerIoData->BytesFrom; PerIoData->DataBuf.len=PerIoData->BytesSend-(BytesTransferred+PerIoData->BytesFrom); PerIoData->BytesSend=PerIoData->BytesSend-(BytesTransferred+PerIoData->BytesFrom); PerIoData->BytesFrom+=BytesTransferred; DWORD SendBytes; WSASend(PerHandleData->Socket,&(PerIoData->DataBuf),1,&SendBytes,0,&(PerIoData->Overlapped),NULL); } else { INetUser*pUser=(INetUser*)PerHandleData->g_pUser; CNetUser*cUser=(CNetUser*)pUser; cUser->SendNextPackage(); } } } } SetEvent(m_Tread); ::CoUninitialize();#ifdef _DEBUG TRACE("接受线程退出\n");#endif return 0;} 如何实现线程内全局变量? vc 如何用vc++ 读取数据库 VC如果给asp文件发请求和读取asp的Request消息啊? 关于Socket编程:connect 文本读写的问题 改变对话框的大小,正好放下一张图片,但高度少了一点点?在线等 一个问题?请帮忙? 关于单选控件 不用EditView和RichEdit,如何做个notepad?(来抢分!!) sprintf里怎么把一个char[20]的字符串加进去? 菜鸟请教双缓冲在哪里添加onerasebgn函数 MFC或者C++有好用的文件传输库么
由于WSASend是异步,此时不一定完成发送数据,
最好将SetEvent放到GetQueuedCompletionStatus里PER_HANDLE_DATA里各自只有一个收发PER_IO_OPERATION_DATA,必然要做很多同步工作
倒不如弄个收发队列,需要收发时,就申请一个新的PER_IO_OPERATION_DATA如果自己搞不定,上传代码,等大牛解决吧。
UINT WINAPI CServerSocket::ProcessIO(LPVOID lpParam)
{
::CoInitializeEx(NULL,COINIT_MULTITHREADED);
//::CoInitialize(NULL);
ServerSocketStruct*ss=(ServerSocketStruct*)lpParam;
CServerSocket*m_pServer=ss->m_pServer;
HANDLE m_Tread=ss->m_Thread;
delete ss;
HANDLE CompletionPort = m_pServer->CompletionPort;
DWORD BytesTransferred;
LPPER_HANDLE_DATA PerHandleData;
LPOVERLAPPED lpOverlapped;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD Flags = 0;
DWORD dwRecv = 0;
VARIANT_BOOL IsOk;
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);
::CoUninitialize();
#ifdef _DEBUG
TRACE("接受线程退出\n");
#endif
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();
#ifdef _DEBUG
TRACE("接受线程退出\n");
#endif
return 0;
}
// 说明客户端已经退出
if(BytesTransferred == 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->BytesSend==0)
{
m_pServer->sis.NotifyInBytes(BytesTransferred);
CTime time=CTime::GetCurrentTime();
SYSTEMTIME systime;
time.GetAsSystemTime(systime);//转成systime
double dtime;
SystemTimeToVariantTime(&systime,&dtime);
PerHandleData->RecentTime=dtime;
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
{
m_pServer->sis.NotifyOutBytes(BytesTransferred);
if(PerHandleData->g_pServer==m_pServer)
{
if(BytesTransferred+PerIoData->BytesFrom<PerIoData->BytesSend)
{
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->DataBuf.buf=PerIoData->Buffer+BytesTransferred+PerIoData->BytesFrom;
PerIoData->DataBuf.len=PerIoData->BytesSend-(BytesTransferred+PerIoData->BytesFrom);
PerIoData->BytesSend=PerIoData->BytesSend-(BytesTransferred+PerIoData->BytesFrom);
PerIoData->BytesFrom+=BytesTransferred;
DWORD SendBytes;
WSASend(PerHandleData->Socket,&(PerIoData->DataBuf),1,&SendBytes,0,&(PerIoData->Overlapped),NULL);
}
else
{
INetUser*pUser=(INetUser*)PerHandleData->g_pUser;
CNetUser*cUser=(CNetUser*)pUser;
cUser->SendNextPackage();
}
}
}
}
SetEvent(m_Tread);
::CoUninitialize();
#ifdef _DEBUG
TRACE("接受线程退出\n");
#endif
return 0;
}