Reh*_*han 125 networking linux unix tcp socket
我在 linux 上运行一个特定的程序,它有时会崩溃。如果你在那之后快速打开它,它会像第一次那样监听套接字 49201 而不是 49200。netstat 显示 49200 处于 TIME_WAIT 状态。
是否有程序可以运行以立即强制该套接字退出 TIME_WAIT 状态?
Eug*_*ota 161
/etc/init.d/networking restart
Run Code Online (Sandbox Code Playgroud)
让我详细说明一下。传输控制协议 (TCP) 旨在成为两个端点(程序)之间的双向、有序且可靠的数据传输协议。在这种情况下,术语可靠意味着如果数据包在中间丢失,它将重新传输数据包。TCP 通过为从对等方接收到的单个或一系列数据包发回确认 (ACK) 数据包来保证可靠性。
这对于诸如终止请求/响应之类的控制信号也是如此。RFC 793将 TIME-WAIT 状态定义如下:
TIME-WAIT - 表示等待足够的时间以确保远程 TCP 收到其连接终止请求的确认。
请参阅以下 TCP 状态图:
![]()
TCP是双向通信协议,所以在建立连接时,客户端和服务器之间没有区别。此外,任何一方都可以调用退出,并且双方都需要同意关闭以完全关闭已建立的 TCP 连接。
让我们将第一个调用退出作为主动接近者,而另一个同级则是被动接近者。当主动关闭器发送 FIN 时,状态进入 FIN-WAIT-1。然后它收到发送的 FIN 的 ACK,状态进入 FIN-WAIT-2。一旦它也从被动关闭器接收到 FIN,主动关闭器将向 FIN 发送 ACK,状态进入 TIME-WAIT。如果被动关闭器没有收到到第二个 FIN 的 ACK,它将重传 FIN 数据包。
RFC 793将超时设置为最大段寿命的两倍,或 2MSL。由于 MSL(数据包可以在 Internet 上徘徊的最长时间)设置为 2 分钟,因此 2MSL 为 4 分钟。由于没有对 ACK 的 ACK,如果它正确遵守 TCP/IP 协议,主动接近器只能等待 4 分钟,以防万一被动发送方没有收到对其 FIN 的 ACK(理论上) .
实际上,丢失的数据包可能很少见,如果这一切都发生在 LAN 内或一台机器内,则非常罕见。
要逐字回答问题,如何在 TIME_WAIT 中强行关闭套接字?,我仍将坚持我原来的答案:
/etc/init.d/networking restart
Run Code Online (Sandbox Code Playgroud)
实际上,我会对其进行编程,使其使用 WMR 提到的 SO_REUSEADDR 选项忽略 TIME-WAIT 状态。 SO_REUSEADDR 究竟是做什么的?
这个套接字选项告诉内核,即使这个端口很忙(在
TIME_WAIT 状态),仍然继续并重用它。如果它很忙,但处于其他状态,您仍然会收到地址已在使用错误。如果您的服务器已关闭,然后在其端口上的套接字仍处于活动状态时立即重新启动,这将很有用。您应该知道,如果出现任何意外数据,可能会混淆您的服务器,虽然这是可能的,但不太可能。
小智 52
我不知道你是否有你正在运行的那个特定程序的源代码,但如果有,你可以设置 SO_REUSEADDR 通过setsockopt(2)它允许你绑定到相同的本地地址,即使套接字处于 TIME_WAIT 状态(除非套接字正在积极侦听,请参阅socket(7))。
有关 TIME_WAIT 状态的更多信息,请参阅Unix 套接字常见问题解答。
小智 34
据我所知,除了将更好的信号处理程序写入程序之外,没有办法强行关闭套接字,但是有一个 /proc 文件可以控制超时所需的时间。该文件是
/proc/sys/net/ipv4/tcp_tw_recycle
Run Code Online (Sandbox Code Playgroud)
您可以通过执行以下操作将超时设置为 1 秒:
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
Run Code Online (Sandbox Code Playgroud)
但是,此页面包含有关设置此变量时可能出现的可靠性问题的警告。
还有一个相关文件
/proc/sys/net/ipv4/tcp_tw_reuse
Run Code Online (Sandbox Code Playgroud)
它控制是否可以重用 TIME_WAIT 套接字(大概没有任何超时)。
顺便说一句,内核文档警告您不要在没有“技术专家的建议/请求”的情况下更改这些值中的任何一个。我不是。
该程序必须已编写为尝试绑定到端口 49200,如果该端口已被使用,则增加 1。因此,如果您可以控制源代码,您可以更改此行为以等待几秒钟,然后在同一端口上重试,而不是递增。
就在这里。您可以使用ss立即销毁所有处于 TIME-WAIT 状态的套接字,如下所示:
ss state time-wait sport = 49200 -K
Run Code Online (Sandbox Code Playgroud)
之后,重新启动侦听器应该会成功,而不是由于Address already in use.
注意:此命令需要超级用户权限。
或者,如果您能够修改程序,则可以在绑定套接字之前简单地设置SO_REUSEADDR ,这样尽管陈旧连接处于 TIME-WAIT 状态,绑定仍然会成功。
| 归档时间: |
|
| 查看次数: |
272731 次 |
| 最近记录: |