FIN_WAIT2 状态是由于关闭连接发起者造成的吗?
Is a FIN_WAIT2 state ever due to a close-connection initiator?
我正在做一些 POSIX 套接字编程,运行 遇到了问题。我编写了一个使用非阻塞套接字的应用程序。因为我目前正在针对正在开发的服务器开发客户端,所以偶尔会发送错误的应用程序级消息。发生这种情况时,我唯一的恢复方法是完全重新建立连接以强制通信进入已知状态。
我通过在非阻塞套接字上发出 POSIX "close()" 来重置连接。然后我请求一个新的套接字并重新建立连接。
但是,我发现的一件事是所有重置都会导致旧连接上的 "FIN_WAIT2"。当 运行 一个 netstat 命令时,有大量 FIN_WAIT2 没有与之关联的 PID(我猜这些被认为是孤立的,可以尝试内核连接超时?)。
无论如何,我很好奇为什么所有这些旧连接都堆积在 netstat 中。我已经阅读了一些关于 TCP 状态的资料,我看到的 FIN_WAIT2 似乎是由于服务器(即在我的情况下不是关闭发起者)没有响应一条消息它成功关闭。这是为什么?
FIN_WAIT2 通常与非关闭启动器端的错误相关联吗?还是我在我的应用程序中做了一些阻止接收 FIN 消息的事情?我使用非阻塞套接字的事实与它有什么关系吗?
总之,是的,您可能在非关闭发起方方面存在错误。它与非阻塞套接字无关。非阻塞套接字只会影响应用程序与其操作系统之间的交互。
了解双方 必须终止套接字连接以便正确清理状态很重要。听起来您的服务器没有关闭套接字的末端。一种可能的情况:
- 服务器创建监听套接字,绑定它等
- 服务器调用
accept
- 客户端调用
connect
创建连接(双方的 TCP 状态移动到 ESTABLISHED
send
/recv
/send
/recv
/etc(状态还是ESTABLISHED
)
- 客户调用
close
;客户端 OS 向服务器发送 FIN
数据包(客户端 OS 将套接字状态移动到 FIN_WAIT1
)
- 服务器 OS 发送
ACK
以确认客户端机器的 FIN
(服务器 OS 将套接字状态移动到 CLOSE_WAIT
;客户端 OS将套接字状态移动到 FIN_WAIT2
)
- 服务器(程序)永远不会关闭其套接字,因此服务器 OS 永远不会发送
FIN
,因此客户端 OS 将保持套接字处于 FIN_WAIT2
状态。 (服务器套接字状态在 CLOSE_WAIT
中表示)
客户端套接字状态可以长时间保持在 FIN_WAIT2
状态,甚至永远,这取决于 OS 实现。例如,Linux 有一个可调变量 tcp_fin_timeout
,指定空闲连接将在 FIN_WAIT2
中保留多长时间;但是 TCP 标准没有指定 FIN_WAIT2
的超时。 (请注意,客户端程序对此一无所知。它已关闭套接字,套接字文件描述符已被销毁,套接字不再可供它访问;这就是全部由操作系统处理。)
如果出现这种情况,您可以尝试重新启动服务器程序(因为当您终止服务器进程时,服务器的操作系统将自动关闭其所有打开的文件,这将导致 FIN
s在任何仍然打开的套接字上发送)。我想您会看到重新启动服务器会导致所有这些客户端套接字进入 TIME_WAIT
状态,它们会在该状态停留一小段时间,然后自行消失。 (是为TIME_WAIT
指定的超时机制。)
另见 TCP 状态图:
我正在做一些 POSIX 套接字编程,运行 遇到了问题。我编写了一个使用非阻塞套接字的应用程序。因为我目前正在针对正在开发的服务器开发客户端,所以偶尔会发送错误的应用程序级消息。发生这种情况时,我唯一的恢复方法是完全重新建立连接以强制通信进入已知状态。
我通过在非阻塞套接字上发出 POSIX "close()" 来重置连接。然后我请求一个新的套接字并重新建立连接。
但是,我发现的一件事是所有重置都会导致旧连接上的 "FIN_WAIT2"。当 运行 一个 netstat 命令时,有大量 FIN_WAIT2 没有与之关联的 PID(我猜这些被认为是孤立的,可以尝试内核连接超时?)。
无论如何,我很好奇为什么所有这些旧连接都堆积在 netstat 中。我已经阅读了一些关于 TCP 状态的资料,我看到的 FIN_WAIT2 似乎是由于服务器(即在我的情况下不是关闭发起者)没有响应一条消息它成功关闭。这是为什么?
FIN_WAIT2 通常与非关闭启动器端的错误相关联吗?还是我在我的应用程序中做了一些阻止接收 FIN 消息的事情?我使用非阻塞套接字的事实与它有什么关系吗?
总之,是的,您可能在非关闭发起方方面存在错误。它与非阻塞套接字无关。非阻塞套接字只会影响应用程序与其操作系统之间的交互。
了解双方 必须终止套接字连接以便正确清理状态很重要。听起来您的服务器没有关闭套接字的末端。一种可能的情况:
- 服务器创建监听套接字,绑定它等
- 服务器调用
accept
- 客户端调用
connect
创建连接(双方的 TCP 状态移动到ESTABLISHED
send
/recv
/send
/recv
/etc(状态还是ESTABLISHED
)- 客户调用
close
;客户端 OS 向服务器发送FIN
数据包(客户端 OS 将套接字状态移动到FIN_WAIT1
) - 服务器 OS 发送
ACK
以确认客户端机器的FIN
(服务器 OS 将套接字状态移动到CLOSE_WAIT
;客户端 OS将套接字状态移动到FIN_WAIT2
) - 服务器(程序)永远不会关闭其套接字,因此服务器 OS 永远不会发送
FIN
,因此客户端 OS 将保持套接字处于FIN_WAIT2
状态。 (服务器套接字状态在CLOSE_WAIT
中表示)
客户端套接字状态可以长时间保持在 FIN_WAIT2
状态,甚至永远,这取决于 OS 实现。例如,Linux 有一个可调变量 tcp_fin_timeout
,指定空闲连接将在 FIN_WAIT2
中保留多长时间;但是 TCP 标准没有指定 FIN_WAIT2
的超时。 (请注意,客户端程序对此一无所知。它已关闭套接字,套接字文件描述符已被销毁,套接字不再可供它访问;这就是全部由操作系统处理。)
如果出现这种情况,您可以尝试重新启动服务器程序(因为当您终止服务器进程时,服务器的操作系统将自动关闭其所有打开的文件,这将导致 FIN
s在任何仍然打开的套接字上发送)。我想您会看到重新启动服务器会导致所有这些客户端套接字进入 TIME_WAIT
状态,它们会在该状态停留一小段时间,然后自行消失。 (是为TIME_WAIT
指定的超时机制。)
另见 TCP 状态图: