int sendCount = 0; // 已经发送的字节数
int left_len = len; // 剩余的字节数
int Times=0; // 发送次数
do{
sendCount = this->Send(sendBuffer + len-left_len, left_len, 0);// CAsyncSocket::Send()
left_len -= sendCount;
}while(left_len > 0)
请问发送大数据包时,比如100M或更大,以上代码在逻辑上好像没问题,但在实际通信中有没有问题呢?
我看到有些代码
在do中添加
Times++;
if(left_len > 0)
::Sleep(200);
在while中控制次数,比如Times<5.
请问这是干什么?

解决方案 »

  1.   

    在本地缓冲区满了以后,如果对方没有接收,你的Send始终返回0或者-1(出错),也就是在对方接收完你的数据包之前,你的CPU几乎全耗在这个循环里了,
    对方可以慢慢收,但是你没有慢慢发
      

  2.   

    谢谢各位的回复。
    (1)year2002提到了缓冲区的问题。
    Socket默认的缓冲区大小是8KB,请问大数据是不是分批传送?比如要传送100KB的数据过去,代码如下:
    int len = 100*1024; // 发送100KB
    LPBYTE sendBuffer = new BYTE[len];
    int sendCount = 0; // 已经发送的字节数 
    int left_len = len; // 剩余的字节数 
    do{ 
    sendCount = this->Send(sendBuffer + len-left_len, left_len, 0);// CAsyncSocket::Send() 
    left_len -= sendCount; 
    }while(left_len > 0) 
    我们知道TCP建立连接之后,如果不断开或者不出现异常,就一直连接。
    下面是MSDN上对Send返回值的说明:
    If no error occurs, Send returns the total number of characters sent. (Note that this can be less than the number indicated by nBufLen.) Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling GetLastError. 
    WSAENETDOWN   The Windows Sockets implementation detected that the network subsystem failed.(Windows套接口实现检测到网络子系统失效)
    WSAENOTCONN   The socket is not connected.(套接口未被连接)
    现假设不断开无异常,请问上面的while循环中,CAsyncSocket::Send是不是前12次发送8KB,第13次发送4KB呢?
    “对方可以慢慢收,但是你没有慢慢发”,请问我给while循环中加一个Sleep,是不是就可以慢慢发了?
    (2)blackcat242和hsuhuasu都提到要考虑返回错误码情况。
         <1>断开,比如接收方突然关闭了应用程序,那么Send返回WSAENOTCONN,然后是不是要break。
         <2>没有断开,而出现异常的情况,又要怎么处理呢?比如接收了一部分,然后异常,然后过一会有正常了,后面是不是涉 及到所谓断点续传的问题?请问又该如何处理呢?
      

  3.   

    个人觉得连接断了就不用再发了,除非它再次请求发送。TCP可以保证无差错的连接,不用管什么断点续传吧~~
      

  4.   

    http://news.jobg.cn/articles/20060909/4887.html
      

  5.   

    如果send发送的字节数<你给他的字节数,那么可能底层缓冲区满了。
    你最好是等会,再尝试发送剩下的字节。
      

  6.   

    int len = 100*1024; // 发送100KB 
    LPBYTE sendBuffer = new BYTE[len];
    int sendCount = 0; // 已经发送的字节数 
    int left_len = len; // 剩余的字节数 
    do{ 
         sendCount = this->Send(sendBuffer + len-left_len, left_len, 0);// CAsyncSocket::Send()      if(sendCount != SOCKET_ERROR)
         {
           left_len -= sendCount;
         }
         else 
         {
            // 中文显示出错信息
            LPVOID lpMsgBuf;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM, 
    0, GetLastError(), 
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // 默认语言
    (LPTSTR)&lpMsgBuf, 0, NULL);
    // 显示
    ::MessageBox(0,(LPCTSTR)lpMsgBuf,_T("GetLastError"),MB_OK|MB_ICONINFORMATION );
    // 释放内存
    ::LocalFree( lpMsgBuf );
            // 退出while循环         
            break;
         }     if(left_len > 0)
           ::Sleep(200); // 慢发送
    }while(left_len > 0)
    delete sendBuffer;当然相应我接收端先读取文件长度,然后要做读状态控制。
    以上代码中就不加次数控制了,直接以剩余字节数作为控制变量。
    正在测试中……
      

  7.   

    也不是说就是发送端要慢慢发,而是发送要根据对方的接受能力来发,比如windows下SOCKET的几种工作模式就是为了解决这些问题的,当然其他平台下都有相应的解决方案。
    比如发送缓冲区满了,你就可以等待发送缓冲区的可写事件来触发发送函数,尽量用SOCKET的消息或者事件模式,而不是用SLEEP