103

我编写了一个与特定端口上的服务器交互的小程序。该程序运行良好,但是:

一旦程序意外终止,并且从此套接字连接显示为CLOSE_WAIT状态。如果我尝试运行一个程序,它会挂起,我必须强制它关闭,这会累积更多的 CLOSE_WAIT套接字连接。

有没有办法刷新这些连接?

4

7 回答 7

89

CLOSE_WAIT意味着您的程序仍在运行,并且尚未关闭套接字(内核正在等待它这样做)。添加-pnetstat获取 pid,然后更有力地杀死它(SIGKILL如果需要)。那应该摆脱你的CLOSE_WAIT套接字。您也可以使用ps来查找 pid。

SO_REUSEADDR用于服务器和TIME_WAIT套接字,因此不适用于此处。

于 2013-04-09T17:30:04.117 回答
43

正如克里斯特克拉克所描述的那样。

CLOSE_WAIT 表示连接的本端已经收到另一端的 FIN,但是 OS 正在等待本端的程序真正关闭它的连接。

问题是您在本地机器上运行的程序没有关闭套接字。这不是 TCP 调整问题。当程序保持连接打开时,连接可以(并且非常正确地)永远保持在 CLOSE_WAIT 中。

一旦本地程序关闭套接字,操作系统可以将 FIN 发送到远程端,在您等待 FIN 的 ACK 时将您转换到 LAST_ACK。一旦收到,连接就完成并从连接表中删除(如果您的终端处于 CLOSE_WAIT状态,那么您最终不会处于 TIME_WAIT 状态)。

于 2013-07-25T11:11:20.603 回答
18

ss您可以使用命令强制关闭套接字;该ss命令是一个用于转储套接字统计信息的工具,并以与 netstat 类似的方式(尽管更简单和更快)显示信息。

要杀死任何处于 CLOSE_WAIT 状态的套接字,请运行此命令(以 root 身份)

$ ss --tcp state CLOSE-WAIT --kill

您还可以过滤您的操作

$ ss --tcp state CLOSE-WAIT '( dport = 22 or dst 1.1.1.1 )' --kill
于 2020-04-10T11:22:23.490 回答
9

即使过多的 CLOSE_WAIT 连接意味着您的代码一开始就有问题,并且这是公认的不好的做法。

您可能想查看:https ://github.com/rghose/kill-close-wait-connections

该脚本所做的是发送连接等待的 ACK。

这对我有用。

于 2014-11-14T10:58:21.560 回答
8

我对最新的 Tomcat 服务器(7.0.40)也有同样的问题。几天没反应一次。

要查看打开的连接,您可以使用:

sudo netstat -tonp | grep jsvc | grep --regexp="127.0.0.1:443" --regexp="127.0.0.1:80" | grep CLOSE_WAIT

本文所述,您可以使用/proc/sys/net/ipv4/tcp_keepalive_time来查看值。该值似乎以秒为单位,默认为 7200(即 2 小时)。

要更改它们,您需要编辑/etc/sysctl.conf.

Open/create `/etc/sysctl.conf`
Add `net.ipv4.tcp_keepalive_time = 120` and save the file
Invoke `sysctl -p /etc/sysctl.conf`
Verify using `cat /proc/sys/net/ipv4/tcp_keepalive_time`
于 2013-07-17T10:46:57.957 回答
3

需要说明的是Socket,客户端和服务端的实例都需要显式调用close()。如果也只有一个端点调用close(),则套接字将保持在 CLOSE_WAIT 状态。

于 2019-02-16T09:04:06.360 回答
1

还值得注意的是,如果您的程序产生一个新进程,该进程可能会继承您打开的所有句柄。即使在您自己的程序关闭之后,那些继承的句柄仍然可以通过孤立的子进程保持活动状态。而且它们在 netstat 中的显示不一定完全相同。但无论如何,当这个子进程还活着时,套接字将在 CLOSE_WAIT 中徘徊。

我有一个运行亚行的案例。如果 ADB 尚未运行,它本身会生成一个服务器进程。这最初继承了我所有的句柄,但在我调查时并没有显示为拥有它们中的任何一个(macOS 和 Windows 也是如此 - 不确定 Linux)。

于 2020-03-02T13:46:04.403 回答