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

时间:2012-10-10 03:46:35

标签: linux sockets 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事件吗?

2 个答案:

答案 0 :(得分:7)

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

  
      
  • 有人在中间拉出一根网线。
  •   
  • 另一端的计算机被破解。
  •   
  • nat gateway inbetween默默地断开连接
  •   
  • 另一端的操作系统崩溃了。
  •   
  • 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);

使用正确的事件相关代码进行设置,良好做法是检查此代码是否为 谨慎如下。

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
     }
}

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

答案 1 :(得分:4)

  

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

部分。 RST在读取时会产生ECONNRESET,而不是EOF,写入时会产生EPIPE。

  

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

单独阅读是不可能的,除非您使用读取超时,例如通过select(),并将超时作为失败,它可能不是。在写入时,您最终将获得EPIPE,但由于缓冲和重试,可能需要一些时间和多次尝试。