我编写了一个与特定端口上的服务器交互的小程序。该程序运行良好,但是:
一旦程序意外终止,并且从此套接字连接显示为CLOSE_WAIT
状态。如果我尝试运行一个程序,它会挂起,我必须强制它关闭,这会累积更多的 CLOSE_WAIT
套接字连接。
有没有办法刷新这些连接?
CLOSE_WAIT
意味着您的程序仍在运行,并且尚未关闭套接字(内核正在等待它这样做)。添加-p
以netstat
获取 pid,然后更有力地杀死它(SIGKILL
如果需要)。那应该摆脱你的CLOSE_WAIT
套接字。您也可以使用ps
来查找 pid。
SO_REUSEADDR
用于服务器和TIME_WAIT
套接字,因此不适用于此处。
正如克里斯特克拉克所描述的那样。
CLOSE_WAIT 表示连接的本端已经收到另一端的 FIN,但是 OS 正在等待本端的程序真正关闭它的连接。
问题是您在本地机器上运行的程序没有关闭套接字。这不是 TCP 调整问题。当程序保持连接打开时,连接可以(并且非常正确地)永远保持在 CLOSE_WAIT 中。
一旦本地程序关闭套接字,操作系统可以将 FIN 发送到远程端,在您等待 FIN 的 ACK 时将您转换到 LAST_ACK。一旦收到,连接就完成并从连接表中删除(如果您的终端处于 CLOSE_WAIT状态,那么您最终不会处于 TIME_WAIT 状态)。
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
即使过多的 CLOSE_WAIT 连接意味着您的代码一开始就有问题,并且这是公认的不好的做法。
您可能想查看:https ://github.com/rghose/kill-close-wait-connections
该脚本所做的是发送连接等待的 ACK。
这对我有用。
我对最新的 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`
需要说明的是Socket
,客户端和服务端的实例都需要显式调用close()
。如果也只有一个端点调用close()
,则套接字将保持在 CLOSE_WAIT 状态。
还值得注意的是,如果您的程序产生一个新进程,该进程可能会继承您打开的所有句柄。即使在您自己的程序关闭之后,那些继承的句柄仍然可以通过孤立的子进程保持活动状态。而且它们在 netstat 中的显示不一定完全相同。但无论如何,当这个子进程还活着时,套接字将在 CLOSE_WAIT 中徘徊。
我有一个运行亚行的案例。如果 ADB 尚未运行,它本身会生成一个服务器进程。这最初继承了我所有的句柄,但在我调查时并没有显示为拥有它们中的任何一个(macOS 和 Windows 也是如此 - 不确定 Linux)。