当TCP keep-alive断开连接时,我会收到什么套接字错误?

9

我有一组带有keep-alive(间隔1分钟)的TCP套接字,由一个select(2)循环(选择读取)控制。

  • 如果一组套接字中的其中一个发生了keep-alive超时,select(2)会返回错误吗?
  • read(2)会返回哪个错误?

如果你在谈论异步套接字选择器,那么你如何期望它选择那些在保持活动状态过期时将会失效的套接字呢? - Germann Arlington
select() 将返回读取通知,然后 recv() 将返回 0,表示远程连接已关闭。 - strkol
1
@strkol 不,除非另一端关闭连接,否则read不会返回0。在这里,没有收到FIN。相反,会返回一个错误(请参见我的答案)。 - Nicholas Wilson
2个回答

5

  • select()本身不会返回错误,即使其中一个套接字已发生错误。[事实上,API无法通过这种方式指示每个套接字的错误,因为在单次select()调用期间,两个不同的套接字都可能获得待处理错误。那么select()会返回哪个呢?]
  • 在每次select()循环迭代后,您可以使用FD_ISSET宏尝试对标记为可读的每个套接字执行read()
  • 任何时候,如果套接字有待处理错误集,则其读事件(和写事件)被触发,并且select()返回,从而允许您立即获取由于保持活动而超时的错误。请注意,select将套接字标记为可读并不表示有数据可供读取,而只是表示读取尝试不会阻塞。如果套接字有待处理错误需要检索,则读取操作不会阻塞。在尝试处理任何数据之前,read(2)write(2)首先检索套接字上的任何待处理错误。

当使用O_NONBLOCK清除的输入函数调用不会阻塞时,描述符将被视为准备好读取,无论函数是否成功传输数据。(该函数可能返回数据,文件结束指示或错误,而不是表示它被阻塞,并且在每种情况下,描述符都应视为准备好读取。)[POSIX:select()]

  • 最后,会返回什么错误?关键在于,它取决于保持活动失败的方式。如果另一端完全消失,您将收到ETIMEDOUT。如果出现数据包传递错误,则将其传递(因此,如果保持活动数据包收到ICMP错误回复,例如“主机不可达”,则会传递EHOSTUNREACH)。[有关这些情况的更多详细信息,请参见Stevens的“Unix网络编程,第1卷”。]

  • 在我的情况下,select 没有返回读取集合的成功。如果它返回读取集合,我就不会有任何问题,因为读取将失败,我会知道套接字已经失效。当套接字发生 keep-alive 超时时,为什么 select 会返回读取集合?套接字并没有真正准备好进行读取。 - CCoder
    1
    Gajanan,我不明白你在说什么。select确实会返回已设置为可读的套接字,并且read无法通知您套接字已死亡。这正是select设置套接字可读的原因:以便您知道发生了什么并可以处理错误。最后,即使没有数据可读,select正确地将套接字标记为可读:手册给出了更精确的描述,“如果读取不会阻塞,则选择标记为读取”。返回错误是即时的(不会阻塞),因此符合文档(请阅读!)。 - Nicholas Wilson
    “Read does fail to inform you the socket is dead”与您评论的其他内容相矛盾。这是您想要表达的吗? - user207421
    @EJP 感谢您的纠正;我本意是说“read不会失败而不通知您”。 - Nicholas Wilson
    1
    POSIX同样指出:“如果套接字有一个挂起的错误,它应该被视为有一个挂起的异常条件”,但Linux不会将这样的套接字放入errfds中。 - Joker_vD

    1

    select() 函数在 FDSET 中设置一个位,指示哪个套接字已触发。使用 FD_ISSET 宏来确定哪个套接字请求服务。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接