读书人

IOCP客户端下载数据服务器崩溃

发布时间: 2012-06-02 14:16:14 作者: rapoo

求助:IOCP客户端下载数据服务器崩溃?
我写了一个IOCP发送和接收程序,发现客户端上传文件没有问题,可是下载服务器数据出现问题。我尝试下载服务器30兆的数据,连续下载5-6次后,服务器流量不断降低,开始还有3兆每秒,后面只有1兆多每秒。如果继续下载,服务器可能崩溃。在即将崩溃的时候,我调试运行,发现有时服务器IOCP的SafeArrayCreateVector创建8192个字节,返回空。更为严重的情况是,有时连创建组件对象都返回空。我开始以为是内存泄露的问题,可是在VC++2005调试运行时,关闭程序没有提示内存泄露。会不会是什么资源发生泄露,还是IOCP的内存锁定的问题,给分100分,请各位专家帮忙看下程序!
首先,我定义的PER_IO_OPERATION_DATA和PER_HANDLE_DATA如下:

C/C++ code
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;} 



[解决办法]
代码发:228330140@qq.com只看上面这些也不能判定是哪个地方出了问题。可能是其他地方
[解决办法]
调试一下啊,看看哪里错误?指针无效?
[解决办法]
检查是不是线程同步问题

举例就WSASend后SetEvent是有问题的
由于WSASend是异步,此时不一定完成发送数据,
最好将SetEvent放到GetQueuedCompletionStatus里

PER_HANDLE_DATA里各自只有一个收发PER_IO_OPERATION_DATA,必然要做很多同步工作
倒不如弄个收发队列,需要收发时,就申请一个新的PER_IO_OPERATION_DATA

如果自己搞不定,上传代码,等大牛解决吧。
[解决办法]
一般来说,malloc返回空,并不是因为内存耗尽,而是堆被破坏了.

你应该首先从堆块越界上找原因。
[解决办法]
你可以在程序的不同位置插入堆检测函数,逐步定位越界的地方。

读书人网 >VC/MFC

热点推荐