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 的超时。 (请注意,客户端程序对此一无所知。它已关闭套接字,套接字文件描述符已被销毁,套接字不再可供它访问;这就是全部由操作系统处理。)

如果出现这种情况,您可以尝试重新启动服务器程序(因为当您终止服务器进程时,服务器的操作系统将自动关闭其所有打开的文件,这将导致 FINs在任何仍然打开的套接字上发送)。我想您会看到重新启动服务器会导致所有这些客户端套接字进入 TIME_WAIT 状态,它们会在该状态停留一小段时间,然后自行消失。 (TIME_WAIT指定的超时机制。)

另见 TCP 状态图: