如果网络崩溃,套接字会发生什么

old*_*ear 3 sockets linux network-programming keep-alive

假设一个简单的网络模型:A已成功创建到B的TCP连接,并且它们正在相互通信

A <----------> B

我知道如果A上的程序死掉(例如核心转储),那么会导致RST数据包到B.所以B的任何读取尝试都将导致EOF,并且B的任何写入尝试都将导致SIGPIPE.我对吗?

但是,如果假设A上的网络出现故障(例如电缆/路由器故障),那么B的读/写尝试会发生什么?在我的情况下,所有套接字都已设置为非阻塞.结果,我不可能检测到网络错误吗?

顺便说一句,我注意到SO_KEEPALIVE套接字中有一个选项可能对我有用http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/.但我想知道如果我将探测间隔设置为2~3秒(默认为75 seoncd)会花费多少?似乎间隔配置是全局配置,那么这会影响机器上的所有插座吗?

最后的问题...说网络已经崩溃,任何写入尝试都会导致EPIPE一段时间后.但是,如果不是尝试写入,我将此套接字置于epoll设备中,那么会发生什么?epoll_wait会返回EPOLLHUP或EPOLLERR事件吗?

Gri*_*han 7

还有许多其他方法可以使TCP连接无法检测到

  • 有人在中间拉出一根网线.
  • 另一端的计算机被破坏了.
  • 中间的nat网关默默地断开连接
  • 另一端的操作系统崩溃了.
  • FIN数据包丢失.
  • 不可检测的错误:在端点在两者之间可丢弃数据包的路由器(包括控制数据包) REFF

在所有情况下,当您尝试通过程序中的SIGPIPE错误写入套接字时,您可以了解它并终止它.

通过read(),无法知道对方是否生活.Thants为什么SO_KEEPALIVE有用.Keepalive是非侵入性的,在大多数情况下,如果你有疑问,你可以打开它而不会有做错事的风险.但请记住,它会产生额外的网络流量,这会对路由器和防火墙产生影响.

这也会影响你机器上的所有插座!(你是对的).并且因为SO_KEEPALIVE会增加流量并消耗CPU.如果应用程序有可能写入断开的连接,最好设置SIGPIPE句柄.

也可以在应用程序的合理位置使用SO_KEEPALIVE.在整个连接持续时间内使用它是很差的(即当服务器在客户端查询上长时间工作时,请使用so_keepalive).

设置探测间隔取决于您的应用程序或说应用程序层协议.

虽然启用TCP keepalive,但您最终会检测到它 - 至少在几个小时内.

假设网络已经崩溃,然而,套接字被插入某个epoll设备而不是尝试写入:

epoll中的第二个参数:

 n = epoll_wait (efd, events, MAXEVENTS, -1);
Run Code Online (Sandbox Code Playgroud)

设置正确的事件相关代码,良好做法是检查此代码是否
谨慎,如下所示.

n = epoll_wait (efd, events, MAXEVENTS, -1);  
for (i = 0; i < n; i++)  
{   
    if ((events[i].events & EPOLLERR) ||
          (events[i].events & EPOLLHUP) ||
          (!(events[i].events & EPOLLIN)))
    {
          /* An error has occured on this fd, or the socket is not
             ready for reading (why were we notified then?) */
      fprintf (stderr, "epoll error\n");
      close (events[i].data.fd);
      continue;
    }

    else if (sfd == events[i].data.fd)
    {
          /* We have a notification on the listening socket, which
         means one or more incoming connections. */

         // Do what you wants
     }
}
Run Code Online (Sandbox Code Playgroud)

其中EPOLLRDHUP的 含义是:
流套接字对等关闭连接,或关闭写入一半的连接.(此标志对于编写简单代码以在使用边缘触发监视时检测对等关闭特别有用.)

  • 您还错过了无法检测到错误的原因:端点之间的路由器以静默方式丢弃数据包.它甚至可能非常糟糕,它允许通过TCP控制数据包(包括SO_KEEPALIVE数据包)并且只丢弃实际数据包.虽然这不太可能不会给`read`或`write`带来问题,但是实现应用程序级keep-alive的另一个原因. (2认同)