系统采用C/S模式。服务器向客户端发送大量数据(文件大小几M到几G不等)。服务器和客户端都的套接字都是从CAsyncSocket派生,连接采用TCP模式。
数据传送流程:(一“问”一“答”)
1.服务器每次向客户端发送4096个字节数据,然后等待客户端确认。
2.客户端在OnReceive里接收数据。如果接收到4096个字节便向服务器发送确认信息,否则继续等待其余的数据。
3.客户端总是在收到4096个字节后才向服务器发送确认信息。
4.服务器在收到客户端的确认信息后再向客户端发送4096个字节的数据。
5.不断重复,直到数据发送完成。
问题描述:
有时候,服务器向客户端发送了4096个字节。而在客户端接收数据的时候,由于网络或者其他原因,客户端一次无法收到4096个字节的数据。我通过写日志的方法发现:客户端只能两次触发OnReceive函数,然后就不再响应了。
经常的情况是:在日志中的记录是——客户端收到了344个字节,然后又收到了344个字节;之后就没有记录了。也就是说,客户端不再收到数据了。但是,服务器端是发送了4096个字节的数据(通过日志的记录知道)。而客户端却没有收到全部的数据。经过我的分析判断得到的问题是:OnReceive在触发了两次后就不再触发了。
我在本地计算机中用127.0.0.1巡回测试也是这样。服务器确实已经发送了4096个字节。因为不存在网络的问题,客户端应该是可以直接收到4096个字节数据的。但是问题依旧。我在网上找了许多关于CAsyncSocket的内容都没有发现这个问题的解决办法。
我的猜想:会不会是粘包的问题??如果是又怎么解决。
期待得到的帮助:
1.如何知道CAsyncSocket派生的类有没有及时收到FD_READ的消息,并且进入了相应的OnReceive函数。(无法单步调试和断点调试,因为这种情况不是经常发生,有时候没有问题,有时候在发送了一部分数据后才出错。我用断点调试时,不会发生错误,我已经用过各类断点多次调试过了。只能是通过写日志的方法记录出错的过程。
2.如何知道接收缓冲区中有没有数据??(我想在客户端没有一次收到4096个字节数据时,利用定时检测接收缓冲区是否有数据,然后手动调用Receive函数接收数据。我也知道,在异步模式下,当有数据到来后会自动产生FD_READ,然后调用OnReceive。但是,目前发现的情况是——在两次调用OnReceive后就没有自动调用OnReceive函数了。这个问题已经困扰了好几天了,希望各位可以尽己所能,鼎力相助。

解决方案 »

  1.   


    void CMyAsyncSocket::OnReceive(int nErrorCode)   // CMyAsyncSocket is 
                                                    // derived from CAsyncSocket
    {
       static int i=0;   i++;   TCHAR buff[4096];
       int nRead;
       nRead = Receive(buff, 4096); 
       
       switch (nRead)
       {
       case 0:
          Close();
          break;
       case SOCKET_ERROR:
          if (GetLastError() != WSAEWOULDBLOCK) 
          {
             AfxMessageBox ("Error occurred");
             Close();
          }
          break;
       default:
          buff[nRead] = 0; //terminate the string
          CString szTemp(buff);
          m_strRecv += szTemp;   // m_strRecv is a CString declared 
                               // in CMyAsyncSocket
          if (szTemp.CompareNoCase("bye") == 0 )    ShutDown();
       }
       CAsyncSocket::OnReceive(nErrorCode);
    }nRead = Receive(buff, 4096); 
    对nRead处理环节上出问题了 ??
      

  2.   

    recvice不能保证一次接收完4096个字节,你要循环接收的吧。
      

  3.   

    把OnReceive包含写日志的相关代码贴上来。再贴上最后一段日志的内容。