TCP 建立一个连接需 3 次握手,而终止一个连接则需要四次挥手。四次挥手的整个过程是这样的:
首先,一方应用程序调用 close,我们称该方为主动关闭方,该端的 TCP 发送一个 FIN 包,表示需要关闭连接。之后主动关闭方进入 FIN_WAIT_1 状态。
接着,接收到这个 FIN 包的对端执行被动关闭。这个 FIN 由 TCP 协议栈处理,我们知道,TCP 协议栈为 FIN 包插入一个文件结束符 EOF 到接收缓冲区中,应用程序可以通过 read 调用来感知这个 FIN 包。一定要注意,这个 EOF 会被放在已排队等候的其他已接收的数据之后,这就意味着接收端应用程序需要处理这种异常情况,因为 EOF 表示在该连接上再无额外数据到达。此时,被动关闭方进入 CLOSE_WAIT 状态。
接下来,被动关闭方将读到这个 EOF,于是,应用程序也调用 close 关闭它的套接字,这导致它的 TCP 也发送一个 FIN 包。这样,被动关闭方将进入 LAST_ACK 状态。
最终,主动关闭方接收到对方的 FIN 包,并确认这个 FIN 包。主动关闭方进入 TIME_WAIT 状态,而接收到 ACK 的被动关闭方则进入 CLOSED 状态。进过 2MSL 时间之后,主动关闭方也进入 CLOSED 状态。
你可以看到,每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。
当然,这中间使用 shutdown,执行一端到另一端的半关闭也是可以的。
当套接字被关闭时,TCP 为其所在端发送一个 FIN 包。在大多数情况下,这是由应用进程调用 close 而发生的,值得注意的是,一个进程无论是正常退出(exit 或者 main 函数返回),还是非正常退出(比如,收到 SIGKILL 信号关闭,就是我们常常干的 kill -9),所有该进程打开的描述符都会被系统关闭,这也导致 TCP 描述符对应的连接上发出一个 FIN 包。
无论是客户端还是服务器,任何一端都可以发起主动关闭。大多数真实情况是客户端执行主动关闭,你可能不会想到的是,HTTP/1.0 却是由服务器发起主动关闭的。
网友评论