1. 为什么产生?当send 在 事件选择 模式下, 成为非堵塞函数,一旦 系统缓存下的时候,就会产生这个错误。那么,recv 何时会产生类似错误呢?  不会也是系统缓存也不够吧。
2. 产生的时候,如何解决? char buf[buffSize];

ZeroMemory(buf,buffSize);

strcpy(buf,"hello");



while(1)
{
int nbytes=send(s,buf,buffSize,0);

//检测错误,处理 系统缓存不够的情形
if( (nbytes==SOCKET_ERROR) && ( GetLastError()==WSAEWOULDBLOCK) )
{

WaitForSingleObject(event1,-1); //这个是我写的,我其实不知道其何时有信号? 时间该设置多久何时呢?
// 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件
WSANETWORKEVENTS event;
::WSAEnumNetworkEvents(s, event1, &event);

if(event.lNetworkEvents & FD_READ) // 处理FD_READ通知消息
{
if(event.iErrorCode[FD_READ_BIT] == 0)
{}
}
else if(event.lNetworkEvents & FD_CLOSE) // 处理FD_CLOSE通知消息
{
if(event.iErrorCode[FD_CLOSE_BIT] == 0)
{
::closesocket(s);
break;

}
}
// 这个才是重点, 处理 系统缓存有空闲了,这里也是 本帖的疑问处:
以下代码是我写的,我感觉不对,比如:nbytest一旦是-1的时候,就悲剧了。 还有,如果以下代码中send再次 错误,该如何啊。
else if(event.lNetworkEvents & FD_WRITE) // 处理FD_WRITE通知消息
{
if(event.iErrorCode[FD_WRITE_BIT] == 0)
{
//继续发送上次的

char* p=buf+nbytes;

nbytes=send(s,buf,buffSize-nbytes,0);

}
}
}
Sleep(500);   //定时器的作用

}

解决方案 »

  1.   

    非阻塞IO模式,recv返回SOCKET_ERROR,WSAGetLastError返回WSAEWOULDBLOCK并不是真正错误,只是操作没有完成
      

  2.   


    不是错误, 那么 recv调用后,getlasterror会产生这个?send是因为系统缓存不够导致的,能理解那recv呢?
      

  3.   

    “nbytes==SOCKET_ERROR”这时候应该是重发了吧。
    “char* p=buf+nbytes;
    nbytes=send(s,buf,buffSize-nbytes,0);”而不应该接着再发吧。
      

  4.   

    那么,recv 何时会产生类似错误呢? 不会也是系统缓存也不够吧。
    --------------
    不是,可能是没有数据,非阻塞IO模型下,,所以你不能以recv的返回值作为判断依据,需要看WSAGetLastError的返回值来判断其真正的原因。你需要用其它机制来判断数据到来,然后调用recv,将数据从系统缓冲区copy到用户缓冲区中。
      

  5.   

    你把buffSize开到几十KB,然后做几次循环,就会进入了 SOCKET_ERROR了根本不是你说的 重发导致的。既然系统缓存不够,那么 这一次的没有发出去,需要再次发送啊。我的逻辑没有错误。
    我的问题在于: 1.    WaitForSingleObject(event1,-1);            //这个是我写的,我其实不知道其何时有信号? 时间该设置多久何时呢?
      2.// 这个才是重点, 处理 系统缓存有空闲了,这里也是 本帖的疑问处:
    以下代码是我写的,我感觉不对,比如:nbytest一旦是-1的时候,就悲剧了。 还有,如果以下代码中send再次 错误,该如何啊。
                else if(event.lNetworkEvents & FD_WRITE)        // 处理FD_WRITE通知消息
                {
                    if(event.iErrorCode[FD_WRITE_BIT] == 0)
                    {
                        //继续发送上次的
                        
                        char* p=buf+nbytes;
                        
                        nbytes=send(s,buf,buffSize-nbytes,0);    
                        
                    }
                }
      char buf[buffSize];
        
        ZeroMemory(buf,buffSize);
        
        strcpy(buf,"hello");
        
        
        
        while(1)
        {
            int nbytes=send(s,buf,buffSize,0);    
            
    //检测错误,处理 系统缓存不够的情形
            if( (nbytes==SOCKET_ERROR) && ( GetLastError()==WSAEWOULDBLOCK) )
            {
                
                WaitForSingleObject(event1,-1);            //这个是我写的,我其实不知道其何时有信号? 时间该设置多久何时呢?
                // 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件
                WSANETWORKEVENTS event;
                ::WSAEnumNetworkEvents(s, event1, &event);
      

  6.   

    recv返回  WSAEWOULDBLOCK 表示在非阻塞模式下,在系统缓冲区中没有可用数据,你需要再次调用recv,或者采用其他的方式 事件,消息,等方式获取。
           WaitForSingleObject(event1,-1);            //这个是我写的,我其实不知道其何时有信号? 时间该设置多久何时呢?
         
    这个地方你应该是对这个socket注册了一个事件,等相应的read,write的时候,你将这个事件set
      

  7.   

    经验证, 说的是对的。当不断的recv的时候,在堵塞模式下,如果没有数据发送,那么recv会堵塞。
    而在非堵塞模式下,就会返回这个错误码。
    当send 在 事件选择 模式下, 成为非堵塞函数,一旦 系统缓存下的时候,就会产生这个错误。

    这句话修改一下,不是错误,是错误码。
      

  8.   

    我觉的还是逻辑上的问题:
    1.按你的代码逻辑,肯定是到了发送缓冲区被写满了,才会进入你的if条件中。(当然,还有一种产生WSAEWOULDBLOCK错误的情况,这里不用考虑)
    2.WaitForSingleObject(event1,-1);是等待注册的套接字上有读、写、关闭事件的时候才会激活,放在这个位置是不合适的。因为你已经调用了send。也就是说信号已经受信了。
    3.你做的这个实际已经类似于异步通信了(只是我的理解)。应该在另外一个线程中WaitForSingleObject(event1,-1);然后做你下面的所有操作。
    4.当if( (nbytes==SOCKET_ERROR) && ( GetLastError()==WSAEWOULDBLOCK) )这个发生的时候,你应该暂停你的while循环,做相应的错误处理。
      

  9.   


    回复你的第2点:放在这里,位置不对, 我却是不知道放哪里合适。需求: 连接后,就隔几秒钟发送一次数据包。 这个是需求。如果错误,我们处理错误。所以send放在while中是由道理的。但是:你第一次发送数据,是你主动发送出去, 岂能调用等待函数呢?肯定不能把 send和等待函数位置交换。就好比, 程序启动后,连接服务单,然后发送数据,第一次发送时候, 如果等待函数在前,send在后, 你说说,等待函数会返回嘛? 怕是很难的。因为没有信号, 计算机怎么就知道何时有信号呢,你只是连接了,没有调用send,这个信号怎么会平白无故诞生呢?  尽管注册了这个事件, 和服务器保持连接了,信号不会凭空而降。所以我把等待函数放在send后面.
      

  10.   


    第3点: 没有2个线程,只有一个
    第4点:你看了没,我已经处理错误了。
     else if(event.lNetworkEvents & FD_WRITE)        // 处理FD_WRITE通知消息
                {
                    if(event.iErrorCode[FD_WRITE_BIT] == 0)
                    {
                        //继续发送上次的
                        
                        char* p=buf+nbytes;
                        
                        nbytes=send(s,buf,buffSize-nbytes,0);    
                        
                    }
                }
    这个难道不是错误处理吗?当然,我的有些问题存在,更正一下,这个套接字,只有2个事件被注册:FD_WRITE, FD_CLOSE , 没有其他事件。       原因是,在这个线程里,我要处理,主动发送数据,如果遭遇了 WSAEWOULDBLOCK,该如何处理错误的问题。            这是需求,目标啊。
      

  11.   


    程序只将套接字注册了事件, 然后连接服务器,其他函数不调用,只调用等待函数, windows可以做到, FD_WRITE产生吗?是不可以的!调用send 可能会产生 FD_WRITE, 但是不调用send, 不可能产生该事件。所以我才搞不懂,这个需求,到底该如何实现啊?谁能提供代码?
      

  12.   

    貌似看懂你的需求了:
    ZeroMemory(buf,buffSize);
        strcpy(buf,"hello");
        buffSize = sizeof(buf); //这里的发送字符大小应该是等于数据大小“char* p=buf+nbytes;
      nbytes=send(s,buf,buffSize-nbytes,0); ”这两句这样修改一下:
        int nPreBytes = 0;
        while(1)
        {
            ....
            if( (nbytes==SOCKET_ERROR) && ( GetLastError()==WSAEWOULDBLOCK) )
            {
                 ....
                 char* p=buf+nPreBytes;
                        
                 nbytes=send(s,buf,buffSize-nPrebytes,0);
                 if(nbytes > 0 && nbytes < (buffSize-nPreBytes))
                 {
                     nPreBytes = nbytes;
                  }
             }else
            {
                  nPreBytes = nbytes;
             }
         }
      

  13.   

    1.  nbytes=send(s,buf,buffSize-nPrebytes,0);
      if(nbytes > 0 && nbytes < (buffSize-nPreBytes))
      {
      nPreBytes = nbytes;
      }
      }else
      {
      nPreBytes = nbytes;
      }if.......else里  的没有看懂2. 我终于发现这个算法 怕是无穷的算法了。请我听一言,让我慢慢道来:当你在FD_WRITE 里再次调用send的时候, 如果再次失败,咋整。貌似这个算法 是很难完成的。while循环开头就有个send如果再次 一旦遇到FD_WRITE ,那么就说明没有完整发送出去,自然得做处理了。
    处理过程中,又再 产生WSAEWOULD,    玩完,这个是什么算法嘛。还有:send 如果成功发送, 也有可能发送了部分,未必就是WSAEWOULD。这个算法太难了。
      

  14.   

    12---13---14楼经本人多次试验验证:可以证明,是错误的, 事件凭空而降有信号, 与注册的事件有关系,如果注册了FD_WRITE,  那么第一次进行循环,(我们把等待函数放到send前面),等待函数是无法堵塞的。如果你注册了FD_READ 或者其他事件,那么就会堵塞。结论:可以把等待函数放到send的前面!!!!多谢各位,可以结贴了。至于算法的实现我却是不会,有机会再研究。
      

  15.   

    今天本人也遇到这样一个问题,别的不解释 给出基本代码
    服务端:接受数据
    while(TRUE)
    {
    nRet = recv(Clientsock,Recbuf1,MAX_PATH,0);
    if(nRet <= 0 )break; }
    客户端发送:nRet = send(Clientsock,"liujiquan has comming!",MAX_PATH/2,0);
    nRet = send(Clientsock,"123!",MAX_PATH/2,0);
    nRet = send(Clientsock,"22222222222!",MAX_PATH,0);经watch框里面,我貌似只能接收到 "liujiquan has comming!", 和 ,"22222222222!", 起始不然。
    第一次 recv的Recbuf1 显示"liujiquan has comming!", 但是起始你会发现
    Recbuf1[Recbuf1[MAX_PATH/2]] = '1';
    Recbuf1[Recbuf1[MAX_PATH/2+1]] = '2';
    Recbuf1[Recbuf1[MAX_PATH/2+2]] = '3';所以你的数据其实是获取到了。
    因为你send的数据大小 为MAX_PATH/2 ,MAX_PATH/2,MAX_PATH 。
    所以一般最好服务和客户端  发送接收大小 保持一致就不出出现这个疑问;
    还有 GetLasetError = WSAEWouldBock 仅仅只是表示 没有数据 可以recv而已。
    不是错误。