TCP 套接字可以注意到网络中断的异常吗?

Posted

技术标签:

【中文标题】TCP 套接字可以注意到网络中断的异常吗?【英文标题】:Can a TCP socket notice the exception of network broken? 【发布时间】:2015-08-25 04:40:16 【问题描述】:

我在 linux 上通过套接字与服务器建立了 tcp 链接。 并且我使用select()函数来监控是否有数据,如果有,我使用recv来获取数据。

现在我想知道网络是否损坏(例如电缆被移除)。 但是即使我监控异常也无法得到异常。

FD_SET( m_socket, &except_fds );

int result = select( m_socket + 1, &fds, 0, &except_fds, timeout == -1 ? 0 : &tv );

让我困惑的是android上有类似的实现(java.net.socket),如果我将手机设置为飞行模式,我可以立即捕获异常。

select() 实现平台是否特定?

总之,如果用这种方法可以监控断网?如果没有,有什么解决办法吗?

【问题讨论】:

【参考方案1】:

TCP 协议的一般工作方式,错误是数据传输失败(不是ACK'd)。除非数据传输失败,否则没有错误。

因此,您可以使用setsockopt SO_KEEPALIVE 或定义一个简单的心跳协议定期发送小数据包以检测断开的连接。您还可以使用TCP_KEEPCNTTCP_KEEPIDLETCP_KEEPINTVL 覆盖keepalive 默认值。

【讨论】:

【参考方案2】:

让我困惑的是android上有类似的实现(java.net.Socket),如果我将手机设置为飞行模式,我可以立即捕获异常。

不太相似。 java.net.Socket 不使用select(),除了在不支持SO_RCVTIMEO 的平台上的读取超时。

select() 是特定于实现平台的吗?

当然。

总之,如果用这种方法可以监控断网?

没有。

如果没有,有什么解决办法吗?

唯一能可靠地检测到断开的 TCP 连接的方法是尝试对其进行写入。最终,在考虑缓冲和重试后,write()send() 和朋友将返回 -1 和 errno == ECONNRESET

【讨论】:

【参考方案3】:

您不需要做任何特别的事情。 TCP 连接的丢失,无论是由于另一端关闭它还是由于错误,都不是例外。您已经在等待套接字可读,如果连接关闭或出错,您的等待就结束了。当等待结束时,您的代码应该已经尝试从套接字读取,因此它应该已经检测到这种情况。

请注意,在大多数平台上,暂时失去连接不会关闭 TCP 连接。在临时连接丢失的情况下,这将非常烦人。事实上,在过去,有些系统具有长期 TCP 连接,但只有在活动时才具有网络连接。即使网络连接被故意禁用,连接仍然有效。此行为是设计使然。

检测 TCP 链接是否仍然可用的最可靠方法是在其上发送数据。如果链路的另一端无法确认数据,则发送最终将超时。 (你调用send函数可能已经返回成功,但是超时会触发错误,使socket可读,调用read函数时会报错。)

【讨论】:

连接失败的方式可能是除了读取超时之外读取永远不会注意到。【参考方案4】:

如果您想检测网络状况的变化,您将需要使用特定的系统服务。

在低级别,您可以使用 udev 中的规则检测网络设备的热插拔或移除。更高的是像 NetworkManager 这样的服务,它将在 DBUS 上进行通信。您可以订阅它以获得网络变化的通知。

如果您不使用 NetworkManager,则取决于您的系统脚本。有些有 ifdown-post 和 ifdown-local。其他人具有您可以运行以响应 DHCP 事件的脚本,其中包括网络拔出。其他人可以运行一些程序来监控网络插头状态,例如 ifplug 或 ifplugd 或 netplugd。

如果您希望内核直接通知您而不是使用系统服务或守护程序,我认为您需要开始使用 netlink 协议来扫描可用的网络设备。

【讨论】:

【参考方案5】:

您可能需要将套接字设置为使用保持活动状态,以便它能够检测连接是否已断开。您需要使用setsocketopt()SO_KEEPALIVE 作为第三个参数。尝试检查this。

【讨论】:

【参考方案6】:

如果select 正在监视的任何文件描述符报告错误,select 将返回。

对于套接字,如果操作系统失去与本地链路层网络的连接,将报告错误。这意味着如果主机完全失去网络连接,select 将返回。当您的互联网电缆被拔掉或您的手机切换到飞行模式时,就会发生这种情况。

但是,如果远程路由器出现故障或远程主机消失,TCP 无法知道远程主机是否可访问。您不太可能收到错误,尤其是当您没有主动与远程主机通信时,因此在您的连接超时之前,您不会意识到任何问题。

【讨论】:

以上是关于TCP 套接字可以注意到网络中断的异常吗?的主要内容,如果未能解决你的问题,请参考以下文章

TCP Socket 无连接超时

套接字异常:没有到主机的路由

java TCP套接字消息中断

Java 套接字:TCP 校验和不正确

在erlang中中断gen_tcp:recv

Web服务器可以处理多少个套接字连接?