如何在TIME_WAIT中强制关闭套接字?


113

我在linux上运行特定程序有时会崩溃。如果之后您快速打开它,它会监听套接字49201,而不是第一次监听49200。netstat揭示49200处于TIME_WAIT状态。

是否有可以运行的程序立即迫使套接字移出TIME_WAIT状态?


1
如果您由于TIME_WAIT服务器上的太多”而在这里,只需跳过前三个答案就可以避免该问题,而无需回答。
Pacerier '16

Answers:


148
/etc/init.d/networking restart

让我详细说明。传输控制协议(TCP)设计为两个端点(程序)之间的双向,有序且可靠的数据传输协议。在这种情况下,术语“可靠”表示如果中间丢失,它将重新传输数据包。TCP通过向回发送从对等方接收的单个或一系列数据包的确认(ACK)数据包来确保可靠性。

对于诸如终止请求/响应之类的控制信号也是如此。RFC 793将TIME-WAIT状态定义如下:

TIME-WAIT-表示等待足够的时间以确保远程TCP收到其连接终止请求的确认。

请参见以下TCP状态图: 替代文字

TCP是双向通信协议,因此在建立连接时,客户端和服务器之间没有区别。而且,任何一个都可以呼叫退出,并且两个对等方都需要同意关闭以完全关闭已建立的TCP连接。

让我们将第一个称为退出的称为主动关闭器,将另一个同行称为被动的关闭器。当主动关闭器发送FIN时,状态进入FIN-WAIT-1。然后,它接收到发送的FIN的ACK,状态进入FIN-WAIT-2。一旦它也从被动关闭器接收到FIN,主动关闭器将ACK发送到FIN,状态进入TIME-WAIT。如果被动关闭器未收到第二个FIN的ACK,它将重新发送FIN数据包。

RFC 793将超时设置为最大段生存时间的两倍,即2MSL。由于MSL(数据包可以在Internet上漫游的最长时间)设置为2分钟,因此2MSL为4分钟。由于没有ACK确认,因此,如果主动关闭器正确遵守TCP / IP协议,则主动关闭器只能等待4分钟,以防万一被动发送方未收到到达其FIN的ACK(理论上) 。

实际上,丢失的数据包可能很少见,如果全部发生在LAN或单个计算机中,则非常罕见。

要逐字回答“如何在TIME_WAIT中强制关闭套接字?” 这个问题,我仍然会坚持原来的回答:

/etc/init.d/networking restart

实际上,我将对其进行编程,以便使用WMR提到的SO_REUSEADDR选项忽略TIME-WAIT状态。 SO_REUSEADDR到底是做什么的?

此套接字选项告诉内核,即使此端口正忙(处于
TIME_WAIT状态),也请继续并重用它。如果繁忙,但是处于另一种状态,您仍然会得到一个已经在使用中的地址错误。如果您的服务器已经关闭,然后在其端口上的套接字仍处于活动状态时立即重新启动,这将很有用。您应该注意,如果有任何意外数据进入,可能会使您的服务器感到困惑,但是虽然有可能,但不可能。


8
好的答案,但不是他问题的正确答案。重新启动网络可以,但是重新启动后可以,因此不正确。
克里斯·黄·利弗

3
@Chris Huang-Leaver,问题是“您是否可以运行一个程序来立即迫使套接字移出TIME_WAIT状态?” 如果重新启动可以考虑运行程序,那么它也是正确的答案。您为什么认为这不对?
尤金·横田

8
WMR有最有用的答案(当我遇到此类问题时,这就是我要做的事情)。重新启动网络太过激烈,无法解决,而且可能比等待超时要花更长的时间。他的问题的正确答案是“否”,但您不能输入两个字母来回答问题:-)
Chris Huang-离开者

6
哦,好的,下次SIGTERM上的某些进程挂起时,我将砸碎计算机,而不是修复它。
长波

通用的是“重启网络服务”。特定位置/etc/init.d/networking是特定于平台的(Debian?),因此其他系统的精确命令行会有所不同(有时相当根本)。我同意其他评论者的观点,这似乎严重过头,并且显然对任何不相关的网络服务都具有破坏性。
三胞胎

51

我不知道您是否具有正在运行的特定程序的源代码,但是如果是这样,则可以设置SO_REUSEADDR setsockopt(2),即使套接字处于TIME_WAIT状态,也可以通过该SO_REUSEADDR 绑定到同一本地地址(除非这样)套接字正在积极监听,请参阅socket(7))。

有关TIME_WAIT状态的更多信息,请参见Unix套接字常见问题解答


但是我没有得到已经绑定的错误。当我再次执行程序时,它在post(123456)中侦听,我也可以看到系统正在显示该端口的TIME_WAIT,但仍然可以连接。为什么?
Jayapal Chandran 2010年

2
即使使用SO_REUSEADDR,仍然可能会出现“地址已在使用中”错误。有关详细信息,请参阅hea-www.harvard.edu/~fine/Tech/addrinuse.html
靖国瑶

@WMR SO_REUSEADDR不会“关闭”套接字。它仅使您可以重用那些已经打开的文件。因此问题仍然是“如何强行关闭其中的插座TIME_WAIT?”
Pacerier '16

这是正确的答案,但问题并不完全正确。至少可以很好地解决我的问题(不像重新启动整个网络一样断开所有其他连接)。
V-Mark

SO_REUSEADDRbind()继续前进;但是如果您随后想收听该套接字,listen()则将EADDRINUSE全部返回。换句话说,此答案可能会帮助使用临时端口的客户端软件,但不能解决服务器软件的问题。
威尔

33

据我所知,除了在程序中编写更好的信号处理程序外,没有办法强制关闭套接字,但是有一个/ proc文件来控制超时时间。该文件是

/proc/sys/net/ipv4/tcp_tw_recycle

您可以通过以下方式将超时设置为1秒:

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 

但是,此页面包含有关设置此变量时可能出现的可靠性问题的警告。

还有一个相关文件

/proc/sys/net/ipv4/tcp_tw_reuse

它控制TIME_WAIT套接字是否可以重用(大概没有任何超时)。

附带地,内核文档警告您在没有“技术专家的建议/要求”的情况下不要更改这两个值。我不是。

必须已编写程序以尝试绑定到端口49200,如果该端口已在使用中,则将其递增1。因此,如果您可以控制源代码,则可以将此行为更改为等待几秒钟,然后在同一端口上重试,而不是递增。


认为后两个示例应该是s / rw / tw /我要编辑,但缺乏足够的代表。

1
取自内核文档:警告。tcp_tw_recycle和tcp_tw_reuse都可能导致问题。在不了解正在使用的节点或启用了该参数的节点所使用的节点之间的网络拓扑的情况下,都不应该启用它。由于该设置,通过知道TCP连接状态的节点(例如防火墙,NAT或负载平衡器)进行的连接可能会开始丢弃帧。连接数量足够多时,该问题将变得明显。

将其设置为1可用于将来的连接,但是那些当前已经打开的连接又如何呢?
Pacerier '16

18

实际上,有一种方法可以杀死连接-killcx。他们声称它可以在连接的任何状态下工作(我尚未验证)。您需要知道发生通信的接口,默认情况下它似乎是eth0。

更新:另一个解决方案是一些Linux发行版的存储库中提供的cutter


3

另一种选择是使用超时为0的SO_LINGER选项。这样,当您强制关闭套接字时,将强制关闭套接字,发送RST而不是进入FIN / ACK关闭行为。这将避免TIME_WAIT状态,并且可能更适合某些用途。


2
它还会丢失任何仍在传输的出站数据,并且可能在另一端引起错误。不建议。
2011年

@EJP早期失败几乎总是正确的选择。网络是不可靠的,而战斗会使事情变慢。崩溃的应用程序不能认为任何数据都能安全地将其识别出来。
东武2014年

1
实际上,我会在另一端是有故障的嵌入式工业总线网关的任何一天建议这样做,该网关通过TCP实现其自己的应用程序层可靠传输,该传输阻止连接永远关闭,除非它收到RST并因此填满该网关的连接限制。那里。我给了你一个非常具体而真实的例子,可悲的是,它需要诉诸于这种黑客。
andyn 2015年

@Tobu Networking不可靠,但是TCP试图做到这一点,而且变得更糟并不意味着可以做得更好,让TCP做好其工作并不意味着要“战斗”。
user207421 '18

2

另一种解决方案是拥有一些可靠的代理或端口转发软件,该软件侦听端口49200,然后使用不同的端口将连接转发至可靠性较差的程序的多个实例之一。HAPROXY浮现在我的脑海。

顺便说一下,您连接的端口很高。您可以尝试使用0-1024范围上方的未使用的。您的系统不太可能使用较低的端口号作为临时端口。


0

TIME_WAIT是套接字编程客户端服务器体系结构中最常见的问题。等待几秒钟,定期尝试是最好的解决方案。对于实时应用程序,他们需要服务器必须立即启动。它们具有SO_REUSEADDR选项。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.