如何在TIME_WAIT中强制closures套接字?

我在Linux上运行一个特定的程序,有时会崩溃。 如果在此之后快速打开它,它会在第49201号套接字上而不是第一次在49200上进行侦听。 netstat显示49200处于TIME_WAIT状态。

有没有一个程序可以运行立即强制该套接字移出TIME_WAIT状态?

     /etc/init.d/networking restart 

    让我详细说一下。 传输控制协议(TCP)被devise为两个端点(程序)之间的双向,有序和可靠的数据传输协议。 在这种情况下,术语“可靠”意味着它将在中间丢失的情况下重传数据包。 TCP通过向从对等体接收的单个或一系列分组发回确认(ACK)分组来保证可靠性。

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

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

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

    TCP是一种双向通信协议,所以build立连接时,客户端和服务器之间没有区别。 另外,任何一个人都可以呼叫退出,并且两个同伴需要同意closures才能完全closuresbuild立的TCP连接。

    我们称第一个叫退出为主动closures,而另一个同伴为被动closures。 当主动closures器发送FIN时,状态进入FIN-WAIT-1。 然后,它接收到发送的FIN的ACK,状态转到FIN-WAIT-2。 一旦从被动闭路器接收到FIN,则主动闭合器将ACK发送到FIN并且状态进入TIME-WAIT。 如果被动封闭器没有收到第二个FIN的ACK,它将重新传输FIN数据包。

    RFC 793将TIME-OUT设置为最大段寿命的两倍,即2MSL。 由于MSL是一个数据包可以在Internet上漫游的最长时间,设置为2分钟,2MSL为4分钟。 由于对ACK没有ACK,主动闭路器如果正确地遵守TCP / IP协议,则只能等待4分钟,以防被动发送器没有收到对其FIN的ACK(理论上) 。

    实际上,丢失的数据包可能很less,如果全部发生在局域网内或单个机器内,则很less见。

    要逐字回答这个问题,如何在TIME_WAIT中强行closures一个套接字呢?我仍然会坚持我原来的答案:

     /etc/init.d/networking restart 

    实际上,我会对它进行编程,以便在提到的WMR中使用SO_REUSEADDR选项忽略TIME-WAIT状态。 SO_REUSEADDR究竟做了什么?

    这个套接字选项告诉内核即使这个端口忙(in
    TIME_WAIT状态),继续并重复使用它。 如果它很忙,但与另一个国家,你仍然会得到一个地址已经在使用中的错误。 如果您的服务器已closures,然后在端口上的套接字仍处于活动状态时立即重新启动,这将非常有用。 你应该知道,如果有任何意外的数据进来,它可能会混淆你的服务器,但这是可能的,这是不可能的。

    我不知道你是否有你正在运行的特定程序的源代码,但如果是这样的话,你可以通过setsockopt(2)来设置SO_REUSEADDR,它允许你绑定同一个本地地址,即使套接字在TIME_WAIT状态(除非该套接字正在主动监听,请参阅socket(7) )。

    有关TIME_WAIT状态的更多信息,请参阅Unix套接字FAQ 。

    据我所知,没有办法强制closures套接字,而不是在程序中写入更好的信号处理程序,但有一个/ proc文件控制超时时间。 该文件是

     /proc/sys/net/ipv4/tcp_tw_recycle 

    你可以通过这样设置超时时间为1秒:

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

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

    还有一个相关的文件

     /proc/sys/net/ipv4/tcp_tw_reuse 

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

    顺带一提,内核文档警告你不要在没有“技术专家的build议/请求”的情况下更改这些值。 我不是。

    该程序必须已被写入尝试绑定到端口49200,然后如果该端口已被使用增加1。 因此,如果您拥有源代码的控制权,您可以将此行为更改为等待几秒钟,然后在同一个端口上再次尝试,而不是递增。

    实际上有一种杀死连接的方法 – killcx 。 他们声称它可以在任何连接状态下工作(我没有证实)。 你需要知道通信发生的界面,但是默认情况下它假设为eth0。

    更新:另一个解决scheme是刀具来到一些Linux发行版的仓库。

    另一个select是使用SO_LINGER选项,其超时时间为0.这样,当closures套接字时被强制closures,发送RST而不是进入FIN / ACKclosures行为。 这将避免TIME_WAIT状态,并可能更适合某些用途。

    另一种解决scheme是使用一些可靠的代理或端口转发软件,在端口49200上侦听,然后使用不同的端口将连接转发到不太可靠的程序的几个实例之一… HAPROXY让人浮想联翩。

    顺便说一句,你连接的端口是相当高的。 您可以尝试使用0-1024范围以上的未使用的。 您的系统不太可能将较低的端口号用作临时端口。

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