采用CAsyncSocketEx进行客户端\服务器socket通讯,期初一切正常,但是通讯一段时间后,Client端无法再收到数据(OnReceive)没有被触发,但是Server还是一直在发送数据,且Send的返回值没有异常,之后就一直保持这种Server发送成功,但Client无法接收的状态。这时如果关闭Server端程序,Client会触发OnReceive,并且能够收到之前应该收到的数据,最后触发OnClose。辅助信息:
1、数据的传输频率是比较的高的,数据量大约每秒32K。
2、在Client端接收数据时,添加Sleep(5),似乎能够延长正确状态的时间。没有sleep,大约2分钟挂;有了sleep,能支持20分钟以上。
3、用了CAsyncSocketEx和CAsyncSocket都试过,没有本质区别,因为可能要支持代理,所以还是希望用CAsyncSocketEx先谢谢了,希望能够有高手能够帮助解决这个问题!

解决方案 »

  1.   


    你在OnReceive里是怎么接收数据的?
    一次全部接收吗?我用的是CAsyncSocket类,在接收信息方面与CAsyncSocketEx不会有差别,下面是我接收数据的方法,不是一次接收,分包接收,不需要Sleep,请参考:char buf[10240];
    ZeroMemory(buf, 10240);
    CString str;
    CString sMessage;int nRead = Receive(buf, 10240);
    switch (nRead)
    {
    case 0:
    Close();
    break;case SOCKET_ERROR:
    if (GetLastError() != WSAEWOULDBLOCK) 
    {
    AfxMessageBox ("Error occurred");
    Close();
    }
    break;//receive message successfully
    default:
    buf[nRead] = 0;
    sMessage = buf; .......
             略
    ....... str += sMessage;
    m_pAsyncSocketClientDlg->ShowMessage(str);
    }
    CAsyncSocket::OnReceive(nErrorCode);处理过程可能有不经典的地方,但原理是标准的,因为接收数据的时候都应该一部分一部分的接收,在缓存区中,只要有数据,就会不停的触发OnRecive,我们需要作的是,不停的接收。你出错的原因我不清楚,可以先试试我的方法。
      

  2.   

    void CMySocket::OnReceive(int nErrorCode) 
    {
    // TODO: Add your specialized code here and/or call the base class
    ReadData();
    if(m_pClient) m_pClient->OnReceive(nErrorCode);
    CAsyncSocketEx::OnReceive(nErrorCode);
    // CAsyncSocket::OnReceive(nErrorCode);
    }void CMySocket::ReadData(void)
    {
    int Result;
    char Buf[1024];
    char * NewBuf; for(;;)
    {
    Result = Receive(Buf, sizeof(Buf)); if(Result == 0)
    {
    m_Connected = false;
    Close();
    return;
    }
    if(Result == SOCKET_ERROR)
    {
    switch(GetLastError())
    {
    case WSAEMSGSIZE:
    //MessageBox(NULL, "The message was too large to fit into the specified buffer and was truncated.", "", MB_OK);
    break; case WSAENETRESET:
    case WSAECONNABORTED:
    case WSAETIMEDOUT:
    case WSAECONNRESET:
    m_Connected = false;
    Close();
    return;
    }
    break;
    } if(m_RecvLen + Result < m_RecvMaxLen)
    {
    memcpy(&m_RecvBuf[m_RecvLen], Buf, Result);
    m_RecvLen += Result;
    }else{
    // NewBuf = new char [m_RecvLen + Result];
    NewBuf = MAlloc(char, m_RecvLen + Result); memcpy(NewBuf, m_RecvBuf, m_RecvLen);
    memcpy(&NewBuf[m_RecvLen], Buf, Result); MFree(m_RecvBuf);
    m_RecvBuf = NewBuf; m_RecvLen += Result;
    m_RecvMaxLen = m_RecvLen;
    }
    m_RecvBytes += Result;
    }
    }
      

  3.   

    ReadData(void)里面为什么要加死循环?
      

  4.   

    我觉得最好放到一个单独的线程里处理,sleep会造成用户界面无响应,而且数据量不小,时间长了,数据处理不过来,就会造成一直在接收数据,无法处理的情况,缓冲区也会满掉,而且客户端sleep虽然可以保证开始的数据处理准确,但是服务端的源源不断的数据进来最后也会把链路堵死,服务器可以加一个更长的sleep,或者将客户端的数据处理单独剥离出来
      

  5.   

    有if(m_RecvLen + Result < m_RecvMaxLen)
    {
    memcpy(&m_RecvBuf[m_RecvLen], Buf, Result);
    m_RecvLen += Result;
    }这一句,如果没有接受完,下次可以继续接受~没有必要加死循环的吧~否则没有接受完无法响应函数了~就变成阻塞的了~
    TCP连接应该不用考虑缓冲区满的情况吧~而且跟OnReceive的不响应也没有关系~
    另外看到//CAsyncSocket::OnReceive(nErrorCode);
    这一行~不知道你CMySocket的基类到底是哪个~
    在OnReceive里面加个断点看看能响应几次~再找原因~我是这么感觉的~
      

  6.   

    首先,出现异常情况的时候,客户端程序并没有停止响应,也就是说没有阻塞。
    其次,这个CMySocket是继承于CAsyncSocketEx的,但是用过CAsyncSocket也是一样的现象。
    再次,在客户端加sleep也不是我的本意,只是加了以后正常的状态能保持的更久罢了。如果抛开代码本身,什么情况下会出现OnReceive被阻塞呢?因为关掉服务器端后,客户端还是能够收到之前应该收到的那些数据的,所以说明这些消息并没有丢掉,只是被阻塞住了。那什么情况会造成这种阻塞呢?
      

  7.   

    现在我改用了SOCKET,接收数据这块代码没做任何的改变,没有再出现问题了。
    我想应该不会是CAsyncSocketEx本身的问题吧,还是应该是使用上的问题吧,谁能够帮上忙,再加分!
      

  8.   

    这上面只能讨论讨论原理性的东西~具体的话不调试也不好说~你贴出来的代码除了for这一句(接受数据没有错~,只是完全没有必要,而且怀疑它会阻塞消息)~都跟例程格式差不多~也看不出来什么~
    试试CAsyncSelect(FD_READ)看能不能响应,另外还是要在OnReceive里面加个断点看看能响应几次,具体在哪一步阻塞消息了`然后找原因`
    我原来也老是遇到这种问题~都是这么解决的~
      

  9.   

    在任何调用On事件的函数体里面加一个AsyncSelect。和Sleep没有关系的,Sleep是把整个线程挂起。这个问题,我也碰到过,纳闷ing!
      

  10.   

    异步socket是基于消息驱动的,按说不进入死循环,不需要显式的指定AsyncSelect,就因该可以触发On事件,但是我也遇到过几次On事件不能触发的问题,后来每次Send或者Recv事件之后都加了一个AsyncSelect效果好很多,没有大数据量的测试,基本在没有出现过消息不能触发的问题。还有就是所有的事件处理要在开Socket的线程内运行,跨线程消息传递不过去。
      

  11.   

    每次系统调用onreceive,你只要确保能把缓冲区数据都读完,就不会有问题。在Onreceive里啥也别干,就do {int Ret = Receive(buf,size) TRACE("");}while(ret == size)。如果运行仍不正常,那就出鬼了!
      

  12.   

    我也遇到这种问题,不响应ONRECEIVE消息,后来换个网络和几台机器,居然好了
      

  13.   

    这个问题的确存在,我在开发大文件传输的过程中,就遇到这个问题。经过试验,发现是CAsyncSocket性能的问题,如果没有好办法就只有自己封装SOCKET了,期待大家有什么简洁的办法可以解决这个问题!