select()ed socket上的socket recv与etimedout失败

sya*_*yam 3 sockets linux

我正在编写一个服务器 - 客户端程序,其中包含以下代码片段以接收数据.

    ret_l = select(readfds+1, &readfds, NULL,  NULL ,NULL);
    if(ret_l != -1)
    {
        if(FD_ISSET(myfd, &readfds))
        {
             ret_l = recv(myfd, buf, size_of_buf_array, 0);
             if(ret_l == -1)
                 return ;
         }
    }
Run Code Online (Sandbox Code Playgroud)

据我所知,select()ed文件描述符上的recv应该没有失败地接收数据.但是我的代码中的recv因错误ETIMEDOUT而失败.有人请告诉我为什么会这样.还请告诉我一些解决方法,即使在ETIMEDOUT之后也能完全接收数据.

Dam*_*mon 6

有三种可能的原因可见ETIMEDOUT:

  1. 连接在内部超时recv,这甚至不太可能发生一次(但肯定不会发生几次).
  2. 您没有检查成功connect,并且连接从未成功建立(可能防火墙正在丢弃连接尝试?).这是可能的原因.
  3. 你的套接字实现被破坏了,这是不太可能的.

select不生成ETIMEDOUT,只生成connectrecv可能生成.虽然select在极少数情况下可以在没有任何东西可以接收时报告准备就绪(较旧的Linux内核,这可能已被修复),但在这种情况下唯一会发生recv阻塞的事情.

recv可能会产生此错误,但是一旦建立连接就不会超时 - 如果你没有拉电缆,或者如nos所指出的那样,NAT网关可能会在几分钟没有做任何事情后超时.如果可以建立连接,则有一条路由,有人正在另一端进行侦听,因此通常没有超时的常规原因(当然,这是可能的,不太可能一直发生).这个错误当然最终如果连接真正超时因为某些原因(无论阻塞)发生,但如果有的话它是一个非常特殊的条件,而不是常规的.

connect 失败是一个条件,你可以想象由于许多原因(无法访问,防火墙,服务器进程没有运行等),并且只要导致它的条件,它就会在每次尝试时经常发生.仍然存在.

至于完全接收数据的解决方法ETIMEDOUT,没有.read将为您提供缓冲区中的内容(最多为您在函数调用中指定的最大值),阻止或失败.这三件事之一,没有别的,永远.
一旦失败,你已经拥有了失败之前可用的所有内容(没有什么可读的了),现在连接已经消失,即套接字不再可用.
您唯一能做的就是创建一个新的套接字并建立一个新的连接,然后再试一次.