在Linux上用C语言如何检测TCP死连接?

4
我在C语言上编写了一个程序,在该程序中客户端发送一次信息给服务器。我使用了TCP套接字。有时候,服务器会进行计算并应该将结果发送给客户端。如何检测到服务器或客户端的连接是否中断?

2
从一般意义上来说,这是不可行的。TCP/IP 协议设计用于不可靠、慢速的连接,因此如果通信双方没有正确关闭连接,那么它需要很长时间才能确定另一个通信方已经离开。但是,断开的电缆或者触发的电源开关会导致丢失回答,但并不表示连接已经中断。顺便提一下,这也是 SSL 心跳扩展的动机,旨在更快地检测到连接是否中断。这可能是您必须要做的:实现某种形式的心跳。只要确保检查缓冲区长度即可 ;-). - Peter - Reinstate Monica
1
这可能会回答你的问题:https://dev59.com/kHHYa4cB1Zd3GeqPNZ2Q - hyde
1
你认为什么是“死”的/“坏”的? - alk
例如,如果客户的程序在我完成之前就已经全部计算完毕。 - user3533019
2
简单的回答是:“遵循你正在TCP之上实现的协议规范。如果它没有指定如何进行操作,那么它就有缺陷,需要进行修复。”当你编写代码来实现一个协议时,你必须遵循该协议的规范。如果协议存在故障或未完全说明,那就不是C编码问题。 - David Schwartz
4个回答

4
你可以尝试使用TCP保活功能。
  # cat /proc/sys/net/ipv4/tcp_keepalive_time
  7200

  # cat /proc/sys/net/ipv4/tcp_keepalive_intvl
  75

  # cat /proc/sys/net/ipv4/tcp_keepalive_probes
  9`

在上面的示例中,如果空闲时间达到7200秒,则TCP保持活动计时器会启动。如果保持活动消息不成功,则它们将在75秒的间隔之后重试。在连续9次重试失败后,连接将被断开。
启动时可以通过在 /etc/init.d 中放置启动脚本来修改 keepalive 时间。

那么,我如何知道连接已经断开了呢?是否存在一种通过系统调用直接更改TCP保活参数的方法? - user3533019
如果TCP keepalive检测到连接中断,那么在下一次发送或接收时会导致ECONNRESET错误。 - user207421

1

在Linux上,有一种方法可以检测死亡的套接字,而不需要读取或写入它们:

  1. 从套接字处理程序中获取数值(uint)文件描述符。
  2. readlink 文件 /proc/[pid]/fd/[#hander]。如果是一个套接字,它将返回类似于 socket:[#inode] 的字符串。
  3. 读取 /proc/net/tcp,查找包含该 inode(第11列)的行。
  4. 读取该行上的状态(st)列(第4列)。如果是0x07(关闭)或0x08(TIME_WAIT),则该套接字已死亡。

0
我所知道的程序确定TCP连接是否已断开的唯一方法是尝试在其上发送数据。该尝试将超时或返回错误条件。因此,程序不需要做任何特殊处理 - 只需发送它设计要发送的内容即可。但是,它确实需要处理所有可能的错误条件。在超时时,它可以重试一段有限的时间或决定连接已断开。如果多次发送相同的数据会有害,则后一种情况是适当的。在此之后或出现错误条件后,程序应关闭当前连接,并在适当的情况下重新建立连接。

这是一种不错的方式,但需要在客户端和服务器中分配一个新的线程来实现。我可以做到,但需要大量资源。而我的程序应该具备高性能。或者还存在其他实现你想法的方式吗? - user3533019
1
@user3533019 相同的线程可以在客户端程序中使用。服务器程序将需要创建一个新的线程,并可能在之前的线程中关闭连接。相比于客户端超时的时间,执行此操作的时间将是微不足道的。 - Steve Emmerson

0

TCP Keep-Alive是一种可靠的方式,用于确定对等方是否已经关闭连接。这是指如果对等方应用程序在没有正确关闭打开的TCP连接情况下退出。

http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html

注意如何使用setsockopt调用为每个套接字启用tcp keep-alives(SO_KEEPALIVE)。

另一种方法是客户端和服务器应用程序在规律的时间间隔内达成心跳协议。如果心跳未到达,则应表明对等方已死亡。


实际上,我发现它们非常不可靠,似乎无法让它们工作。我认为最好的方法是实现一个心跳机制。 - Epic Speedy

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