如何删除 CLOSE_WAIT 套接字连接
Posted
技术标签:
【中文标题】如何删除 CLOSE_WAIT 套接字连接【英文标题】:How do I remove a CLOSE_WAIT socket connection 【发布时间】:2013-04-01 11:58:15 【问题描述】:我编写了一个与特定端口上的服务器交互的小程序。该程序运行良好,但是:
一旦程序意外终止,并且从此套接字连接显示为CLOSE_WAIT
状态。如果我尝试运行一个程序,它会挂起,我必须强制它关闭,这会累积 更多 CLOSE_WAIT
套接字连接。
有没有办法刷新这些连接?
【问题讨论】:
你不能(也不应该)。 CLOSE_WAIT 是 TCP 定义的状态,用于关闭连接,等待对方确认。 另请参阅 unix.stackexchange.com/questions/10106/… ... 我不会重复投票,因为它最终会将问题作为题外话结束。 @vonbrand 不,不是,恰恰相反。它是已被对等方关闭并正在等待本地应用程序关闭其结束的连接的状态。 如果你使用 Commons HttpClient 那么nuxeo.com/blog/… 有很多相关信息。来自 RFC 2616 第 14 节:不支持持久连接的 HTTP/1.1 应用程序必须在每条消息中包含“关闭”连接选项。 【参考方案1】:您可以使用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
【讨论】:
这应该是最佳答案。 我们可以应用过滤器来只杀死特定的端口吗? @MohammadFaisal 是的,当然;您可以通过源或目标端口杀死(或列出)所有套接字,如下所示:sudo ss --tcp --kill sport = 54576 or dport = :ssh
@MustaphaHadid:谢谢。这是一个有用的答案,但在我的情况下ss
的结果是tcp 0 0 1.1.16.1:57212 1.1.16.28:8081 CLOSE_WAIT -
,没有进程ID,因此--kill
不成功。因此我无法释放此端口57212
。【参考方案2】:
还值得注意的是,如果您的程序生成一个新进程,该进程可能会继承您打开的所有句柄。即使在您自己的程序关闭之后,那些继承的句柄仍然可以通过孤立的子进程保持活动状态。而且它们在 netstat 中的显示不一定完全相同。但不管怎样,当这个子进程处于活动状态时,套接字将在 CLOSE_WAIT 中徘徊。
我遇到了一个运行 ADB 的案例。如果 ADB 尚未运行,它本身会生成一个服务器进程。这最初继承了我所有的句柄,但在我调查时并没有显示为拥有它们中的任何一个(macOS 和 Windows 也是如此 - 不确定 Linux)。
【讨论】:
【参考方案3】:需要说明的是,客户端和服务端的Socket
实例都需要显式调用close()
。如果只有一个端点调用close()
,那么套接字将保持在 CLOSE_WAIT 状态。
【讨论】:
【参考方案4】:如Crist Clark所述。
CLOSE_WAIT 表示连接的本地端收到了一个 FIN 来自另一端,但操作系统正在等待该端的程序 本地端实际关闭其连接。
问题是你在本地机器上运行的程序不是 关闭套接字。这不是 TCP 调整问题。一个连接可以 (并且非常正确)在程序中永远停留在 CLOSE_WAIT 保持连接打开。
一旦本地程序关闭套接字,操作系统就可以将 FIN 发送到 在您等待时将您转换到 LAST_ACK 的远程端 FIN 的 ACK。一旦收到,连接就完成了 并从连接表中删除(如果你的结束在 CLOSE_WAIT 你 不要最终进入 TIME_WAIT 状态)。
【讨论】:
如何关闭套接字?? 你关闭你打开的套接字的句柄。使用close()
或closesocket()
,具体取决于您使用的平台。
@RemyLebeau 我想真正的问题是如何在它不会自动发生的情况下进行接线。为什么不关闭套接字?它不能等待传入的数据(因为 FIN 它会被取消)。这样的读操作的错误情况是否响应失败?【参考方案5】:
即使过多的 CLOSE_WAIT 连接意味着您的代码一开始就有问题,这是公认的不好的做法。
您可能想查看:https://github.com/rghose/kill-close-wait-connections
此脚本的作用是发送连接等待的 ACK。
这对我有用。
【讨论】:
你将行为发送到关闭等待套接字。不工作..如果工作,为什么? 我猜,操作系统已经将 FIN 发送到远程主机。远程主机可能无法回复套接字所期望的 ACK。 是的,没错(来自内核代码)。但是我也怀疑你发送的数据包的seq,是“10”,内核不检查吗? 可能不会。我想我尝试了许多随机数,它们似乎有效。【参考方案6】:我在使用最新的 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
如this post 中所述,您可以使用/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`
【讨论】:
答案令人困惑。您说无响应状态已经消失了好几天。但是您还尝试将保持活动时间设置为仅 120 秒。即使使用默认值(7200 秒),它也不应该持续几天,对吧?【参考方案7】:CLOSE_WAIT
表示您的程序仍在运行,并且尚未关闭套接字(内核正在等待它这样做)。将-p
添加到netstat
以获取pid,然后更强有力地杀死它(如果需要,使用SIGKILL
)。那应该摆脱您的CLOSE_WAIT
套接字。您也可以使用ps
来查找pid。
SO_REUSEADDR
用于服务器和TIME_WAIT
套接字,因此不适用于此处。
【讨论】:
好吧...如果该程序打开大量连接,则终止进程可能不是最好的,只有少数那些留在“CLOSE_WAIT”中:在这种情况下,终止进程可能是完全不可能的或不合适(该程序仍然可以工作并提供服务,以及其他连接)。只是关闭挂起的连接会更合适。但实际上通常是程序本身没有在本地关闭连接(CLOSE_WAIT 表示它从另一端收到“FIN”,程序只需要在本地关闭连接)。错误报告可能是合适的以上是关于如何删除 CLOSE_WAIT 套接字连接的主要内容,如果未能解决你的问题,请参考以下文章