求助:IOCP客户端下载数据服务器崩溃?
我写了一个IOCP发送和接收程序,发现客户端上传文件没有问题,可是下载服务器数据出现问题。我尝试下载服务器30兆的数据,连续下载5-6次后,服务器流量不断降低,开始还有3兆每秒,后面只有1兆多每秒。如果继续下载,服务器可能崩溃。在即将崩溃的时候,我调试运行,发现有时服务器IOCP的SafeArrayCreateVector创建8192个字节,返回空。更为严重的情况是,有时连创建组件对象都返回空。我开始以为是内存泄露的问题,可是在VC++2005调试运行时,关闭程序没有提示内存泄露。会不会是什么资源发生泄露,还是IOCP的内存锁定的问题,给分100分,请各位专家帮忙看下程序!
首先,我定义的PER_IO_OPERATION_DATA和PER_HANDLE_DATA如下:
typedef struct{ OVERLAPPED Overlapped; WSABUF DataBuf; char Buffer[MAX_BUFFER_SIZE]; DWORD BytesSend; 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; LPPER_IO_OPERATION_DATA wPerIoData;}PER_HANDLE_DATA,*LPPER_HANDLE_DATA; PER_HANDLE_DATA中,PerIoData表示接收的IO,wPerIoData表示发送的IO。MAX_BUFFER_SIZE为8192。我发送的思路是,在我自定义的INetUser接口中,添加了PostMessage方法,该方法一般在服务器接收数据线程里面收到数据包后调用。PostMessage的思路是:在NetUser组件对象中,创建包队列,PostMessage将包按8192字节划分子包,按顺序添加至队列中,如果开始队列为空,将队列第一个包取出,使用WSASend发送。在在服务器接收数据线程,处理发送消息。如果当前包没有发完,继续WSASend投递,否则调用NetUser组件对象的SendNextPackage继续下一个包的投递。 代码如下: void CNetUser::SendNextPackage(){ //DWORD dwRet=WaitForSingleObject(m_hux,INFINITE); //if(dwRet==WAIT_FAILED) return; if(bClosed!=0) return; WaitForSingleObject(m_sendEvent,INFINITE); if(sendingPackage.GetSize()==0) { SetEvent(m_sendEvent); //SetEvent(m_hux); return; } sendingPackage.GetAt(0)->Release(); sendingPackage.RemoveAt(0); if(sendingPackage.GetSize()==0) { SetEvent(m_sendEvent); //SetEvent(m_hux); return; } IDataPackage*subPack=sendingPackage.GetAt(0); LONG length; subPack->get_CurrentPackageSize(&length); length+=PACKAGE_HEADER; OLE_HANDLE pin; subPack->GetStreamPtr(&pin); BYTE*bbuff=(BYTE*)pin; char*buff=(char*)bbuff; memcpy(lpHandleData->wPerIoData->Buffer,buff,length); lpHandleData->wPerIoData->BytesSend=length; lpHandleData->wPerIoData->DataBuf.buf=lpHandleData->wPerIoData->Buffer; lpHandleData->wPerIoData->DataBuf.len=length; DWORD dwSend; DWORD Flags=0; int len=0; ZeroMemory(&(lpHandleData->wPerIoData->Overlapped),sizeof(OVERLAPPED)); WSASend(lpHandleData->Socket, &lpHandleData->wPerIoData->DataBuf, 1, &dwSend, Flags, &lpHandleData->wPerIoData->Overlapped, NULL); SetEvent(m_sendEvent); //SetEvent(m_hux);}STDMETHODIMP CNetUser::PostMessage(IDataPackage*pdr,DataPackageCoderType type,VARIANT_BOOL*pVal){ AFX_MANAGE_STATE(AfxGetStaticModuleState()); *pVal=VARIANT_FALSE; WaitForSingleObject(m_sendEvent,INFINITE); if(lpHandleData==NULL) { SetEvent(m_sendEvent); return S_OK; } IDataPackageSender*pSender; ::CoCreateInstance(CLSID_DataPackageSender,NULL,CLSCTX_INPROC_SERVER,IID_IDataPackageSender,(void**)&pSender); pSender->put_DataPackageEncodeType(type); VARIANT_BOOL IsOk; pSender->SetSendingDataPackage(pdr,&IsOk); if(!IsOk) { pSender->Release(); SetEvent(m_sendEvent); return S_OK; } LONG oldSize=sendingPackage.GetSize(); IDataPackage*subPack; while(true) { pSender->GetNextPackage(&subPack); if(subPack==NULL) break; sendingPackage.Add(subPack); } pSender->Release(); if((oldSize==0)&&(sendingPackage.GetSize()>0)) { subPack=sendingPackage.GetAt(0); LONG length; subPack->get_CurrentPackageSize(&length); length+=PACKAGE_HEADER; OLE_HANDLE pin; subPack->GetStreamPtr(&pin); BYTE*bbuff=(BYTE*)pin; char*buff=(char*)bbuff; memcpy(lpHandleData->wPerIoData->Buffer,buff,length); lpHandleData->wPerIoData->BytesSend=length; lpHandleData->wPerIoData->DataBuf.buf=lpHandleData->wPerIoData->Buffer; lpHandleData->wPerIoData->DataBuf.len=length; DWORD dwSend; DWORD Flags=0; int len=0; ZeroMemory(&(lpHandleData->wPerIoData->Overlapped),sizeof(OVERLAPPED)); WSASend(lpHandleData->Socket, &lpHandleData->wPerIoData->DataBuf, 1, &dwSend, Flags, &lpHandleData->wPerIoData->Overlapped, NULL); } SetEvent(m_sendEvent); *pVal=VARIANT_TRUE; return S_OK;}