TCP 连接还有许多其他方式可以在未被检测到的情况下失效
- 有人拔出中间的网线。
- 另一端的电脑被核弹了。
- 中间的 nat 网关静默断开连接
- 另一端的操作系统严重崩溃。
- FIN 数据包丢失。
- 不可检测的错误:端点之间的路由器可能会丢弃数据包。(包括控制数据包)
ref
在所有情况下,当您尝试通过程序中的 SIGPIPE 错误在套接字上写入并终止它时,您都可以知道它。
通过 read() 无法知道对方是否存活。为什么 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 的意思是:
Stream socket peer 关闭连接,或者关闭写入一半的连接。(此标志对于编写简单代码以在使用边缘触发监视时检测对等关闭特别有用。)