因为有比较大的数据需要传送,所以我采取把大数据拆分了发,先使用Send发送,遇到缓冲区满了后再使用Onsend继续发,但是每次总是在Send工作一会儿发了几匹数据包以后,Send返回WSAEWOULDBLOCK 后,就再也不触发OnSend消息了,真是百思不得其解,觉得CAsyncSocket问题太多了,难道是BUG?
部分发送代码如下 
BOOL CClientSocket::SendCmd()
{
//如果缓冲区数据尚未发送完毕,直接返回
if(m_cSendBuffer.size() == 0)
return TRUE; CString strText;
strText.Format("Send发送数据");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);

while  (m_nBytesSent < m_cSendBuffer.size())
{  
int  dwBytes = Send(m_cSendBuffer.GetBuffer()  +  m_nBytesSent,    
m_cSendBuffer.size()  -  m_nBytesSent);  
int dwError = GetLastError(); strText.Format("Send发送了%d个数据",dwBytes);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);

if  (dwBytes ==  SOCKET_ERROR)  
{  
if  (dwError ==  WSAEWOULDBLOCK)  break;  
else  
{  
strText.Format("Send发送出现错误%d",dwError);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
break;
}  
}  
else  
{  
m_nBytesSent  +=  dwBytes;  
m_timeLast = CTime::GetCurrentTime();
}  
}  
if  (m_nBytesSent  >=  m_cSendBuffer.size())  
{  
m_nBytesSent = 0;  
m_cSendBuffer.clear(); strText.Format("Send发送完毕");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
}  return TRUE;
}void CClientSocket::OnSend(int nErrorCode) 
{
CString strText;
strText.Format("OnSend发送数据");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText); while  (m_nBytesSent < m_cSendBuffer.size())
{  
int  dwBytes = Send(m_cSendBuffer.GetBuffer()  +  m_nBytesSent,    
m_cSendBuffer.size()  -  m_nBytesSent);  
int dwError = GetLastError();

strText.Format("OnSend发送了%d个数据",dwBytes);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText); if  (dwBytes ==  SOCKET_ERROR)  
{  
if  (dwError ==  WSAEWOULDBLOCK)  break;  
else  
{  
strText.Format("Send发送出现错误%d",dwError);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
break;

}  
else  
{  
m_nBytesSent  +=  dwBytes;  
}  
}  
if  (m_nBytesSent  >=  m_cSendBuffer.size())  
{  
m_nBytesSent = 0;  
m_cSendBuffer.clear(); strText.Format("OnSend发送完毕");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
}  

m_timeLast = CTime::GetCurrentTime();
CAsyncSocket::OnSend(nErrorCode);
}这是记录的日志
2009-03-20 18:21:28.901    Send发送数据
2009-03-20 18:21:28.901    Send发送了-1个数据
2009-03-20 18:21:32.926    OnSend发送数据
2009-03-20 18:21:32.926    OnSend发送了58012个数据
2009-03-20 18:21:32.926    OnSend发送完毕
2009-03-20 18:21:33.097    Send发送数据
2009-03-20 18:21:33.097    Send发送了-1个数据
2009-03-20 18:23:07.362    OnSend发送数据
2009-03-20 18:23:07.362    OnSend发送了50056个数据
2009-03-20 18:23:07.362    OnSend发送完毕
2009-03-20 18:23:07.432    Send发送数据
2009-03-20 18:23:07.432    Send发送了-1个数据然后就再也收不到Onsend消息了。

解决方案 »

  1.   

    if  (dwError ==  WSAEWOULDBLOCK)  break; 
    这里不要break,可以换为
    if  (dwError ==  WSAEWOULDBLOCK)  {Sleep(0);continue;}
      

  2.   


    BOOL CClientSocket::SendCmd()
    {
        while  (m_nBytesSent < m_cSendBuffer.size())
        {  
            int  dwBytes = Send(...);  
    ......        
            if  (dwBytes ==  SOCKET_ERROR)  
            {  
                if  (dwError ==  WSAEWOULDBLOCK)
    {
    //break;
    Sleep(10) ; //把这里这样改下试试
    continue;   //把这里这样改下试试
    }
                else  
                {  
                    strText.Format("Send发送出现错误%d",dwError);
                    LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
                    break;
                }  
            }
    }
    ......

        return TRUE;
    }
    void CClientSocket::OnSend(int nErrorCode) 
    {    
        CString strText;
        strText.Format("OnSend发送数据");
        LOG_DEBUG_INFO( g_strNetworkLogPath, strText);//调试的加上,以后可去掉,不用考察此函数
    }
      

  3.   

    CAsyncSocket 本来就是异步的,楼上几位代码,那岂不是成了阻塞式的了?
    我这可是服务器端程序,需要给几百人服务的,按照楼上写法,能因为一个用户阻塞全部其他用户的服务?
      

  4.   


    如此说至少要用[重叠IO 完成例程]
    最好用IOCP(完成端口) 
      

  5.   

    在OnSend上设置断点执行不到吗?中间还执行了哪些操作?
      

  6.   

    发送的数据太频繁,阻塞了??
    增加一些信息,block后,程序在哪里阻塞了
      

  7.   

    每次Send()都会触发OnSend(), 你想要"先使用Send发送,遇到缓冲区满了后再使用Onsend继续发",这个思路不对.两点建议供参考
    1. 不要用while()循环, 因为Send()会触发OnSend(), 所以它已经有了内在的循环机制.
    2. 对大数据,只要标记上次发送的结束位置,就可以做到分段发送了.
      

  8.   

    你们都没明白我的意思,就是为什么消息会阻塞?为什么我工作了一会儿就再也收不到Onsend消息?
      

  9.   

    兄弟,另1个贴子真地把分给俺了,俺有点惭愧,这个贴子俺不要分了,共同学习其实楼上有几个精彩的回答,你可能没细看,我与你分说一下5L 6L 回贴是让你调试....
    你程序现在的状态根本不是阻塞(专指sokcet阻塞,不是水龙头阻塞)的问题,这点我可以很负责任地告诉你。
    你现在的问题是出错了,5L6L说了调试的2个办法
    我给你加2点
    把CAsyncSocket::OnSend(nErrorCode);//这行去掉,同时看下行
    接收端只接收,不任何处理,把接收端处理数据发生错误的可能性排除,socket通常2端一起测的
    10L 是说如果调试都没问题,可能问题出在这了
      

  10.   

    不是没明白你的意思,是从你的描述中还不足以分析出问题。从上面代码和日志记录中只能知道在Send返回-1后没有“OnSend发送数据”的记录,可能的原因有很多,有可能没有产生消息,也有可能消息丢失,或者消息循环阻塞,或者在记录日志时出现了问题等情况。
    现在需要先知道消息循环是否正常,还有你的程序在执行了SendCmd之后还有没有其它操作。
      

  11.   

    算了吧,最后决定放弃MFC了,太垃圾
      

  12.   

    你可以自己多增加log日志等信息,因为很多时候问题定位都需要一些信息等来分析,可以提高自己分析能力等
      

  13.   

    需要怎么增加日志?
    我刚才把客户端由CAsyncSocket换成了CSocket,发现问题更严重了,接收服务器几个数据包后,就再也收不到OnReceive消息了,线程也没死,因为客户端发送给服务器的消息服务器还能够收到,MFC的消息机制,就是垃圾一个,没办法
      

  14.   


    错误的很明显的了.void CClientSocket::OnSend(int nErrorCode) 
    {    
        CString strText;
        strText.Format("OnSend发送数据");
        LOG_DEBUG_INFO( g_strNetworkLogPath, strText);    while  (m_nBytesSent < m_cSendBuffer.size())
        {  
            int  dwBytes = Send(m_cSendBuffer.GetBuffer()  +  m_nBytesSent,    
                m_cSendBuffer.size()  -  m_nBytesSent);  
            int dwError = GetLastError();
            
            strText.Format("OnSend发送了%d个数据",dwBytes);
            LOG_DEBUG_INFO( g_strNetworkLogPath, strText);        if  (dwBytes ==  SOCKET_ERROR)  
            {  
                if  (dwError ==  WSAEWOULDBLOCK)  break;  
                else  
                {  
                    strText.Format("Send发送出现错误%d",dwError);
                    LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
                    break;
                } 
            }  
            else  
            {  
                m_nBytesSent  +=  dwBytes;  
            }  
        }  
        if  (m_nBytesSent  >=  m_cSendBuffer.size())  
        {  
            m_nBytesSent = 0;  
            m_cSendBuffer.clear();        strText.Format("OnSend发送完毕");
            LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
        }  
        
        m_timeLast = CTime::GetCurrentTime();            
        CAsyncSocket::OnSend(nErrorCode);
    }
    上面代码,
    if  (dwError ==  WSAEWOULDBLOCK)出现这样错误,程序已经告诉你系统缓冲区满,你不能再发送.但代码最后你又出来个CAsyncSocket::OnSend(nErrorCode);
    出现缓冲区满的错误时,你是什么都不做,直接返回.然后等程序接收到FD_WRITE的消息,这是系统告诉你的程序,"缓冲区有空间了,你可经继续发送数据",这时侯才是你继续调用onsend()的时侯.
      

  15.   

    应该不会是这个问题,微软MSDN上的例子也是这么写
    // CMyAsyncSocket is derived from CAsyncSocket and defines the 
    // following variables:
    //    CString      m_sendBuffer;   //for async send
    //    int      m_nBytesSent;
    //    int      m_nBytesBufferSize;void CMyAsyncSocket ::OnSend(int nErrorCode)
    {
       while (m_nBytesSent < m_nBytesBufferSize)
       {
          int dwBytes;      if ((dwBytes = Send((LPCTSTR)m_sendBuffer + m_nBytesSent, 
             m_nBytesBufferSize - m_nBytesSent)) == SOCKET_ERROR)
          {
             if (GetLastError() == WSAEWOULDBLOCK) break;
             else
             {
                TCHAR szError[256];
                wsprintf(szError, "Server Socket failed to send: %d", 
                   GetLastError());
                Close();
                AfxMessageBox (szError);
             }
          }
          else
          {
             m_nBytesSent += dwBytes;
          }
       }
       if (m_nBytesSent == m_nBytesBufferSize)
          {
             m_nBytesSent = m_nBytesBufferSize = 0;
             m_sendBuffer = "";
          }
       CAsyncSocket::OnSend(nErrorCode);
    }