1. 前言

上一章节分析了 TCP 建立连接的过程,既然有建立连接,对应的也有断开连接。数据传输完成之后,客户端和服务器端保持通信状态会占用资源开销,所以需要断开连接,TCP 协议中断开连接也被称为 TCP 四次挥手。

2.1 TCP 四次挥手

面试官提问: 说明一下 TCP 断开连接的过程,涉及到了几个步骤?

题目解析:

图片描述

(TCP 四次挥手过程)

首先从行为上分析,TCP 断开连接总共需要发送四次报文,也就是 "四次挥手" 的过程。

我们定义发送报文的一方是客户端,接收报文的一方是服务器端。

上一章节中已经对三次握手过程做出了分析,在建立连接后到传输数据的整个过程,客户端和服务器端均处于 ESTABLISHED(监听)状态,之后四次挥手的过程如下:
(1)第一次挥手:客户端发送一个请求结束报文,其中 FIN 标志位设置为 1,报文中给定一个序列号 u,报文内容是 FINbit=1 seq=u,发送之后主动进入 FIN_WAIT 状态,等待服务器端的确认报文;

(2)第二次挥手:服务器端收到 FIN 报文,会发送 ACK 确认报文,并且把客户端发送的序列号加一作为确认报文的确认号,表示已经收到了客户端的报文,所以报文内容是 ACKbit=1 seq=v ack=u+1,之后进入 CLOSE_WAIT(关闭等待)状态。此时会通知应用层的进程,客户端已经不会再发送数据了。此时连接处于半关闭状态,如果服务器端发送数据,客户端还是需要接收。

客户端收到第二次挥手的报文后,会进入 FIN_WAIT_2(等待结束)状态,等待服务器发送最后的终止连接报文;

(3)第三次挥手:服务器端把最后的数据发送之后,就开始向客户端发送请求结束报文,FIN 标志位设置为 1,确认号设置为 u+1,比较特殊的一点是报文中 ACK 标志位也是 1,报文内容是 FINbit=1 ACKbit=1 seq=w ack=u+1,发送之后服务器端进入 LAST_ACK(最终确认)状态,等待客户端的确认报文。

(4)第四次挥手:客户端收到服务器的请求断开连接报文后,必须还要发出一个确认报文,ACK 标志位设置为 1,并且序列号同上一报文的确认号,确认号同上一报文的序列号加一,报文内容是 ACKbit=1 seq=u+1 ack=w+1,之后客户端进入 TIME_WAIT(时间等待)状态。因为不会再收到服务器端的报文,所以等待 2*MSL(最大报文段生存时间)之后,自动进入 CLOSED(关闭)状态。

服务器端在收到客户端的第四次挥手报文后,立即进入 CLOSED(关闭)状态,表示结束本次 TCP 连接。

在向面试官分析整个流程的时候,我们可以将四次报文中的第一次和第二次看作一个整体,即是客户端发送请求结束报文以及收到对应响应。第三次和第四次又是一个整体,即服务器端发送请求结束报文并且收到客户端的响应。

2.2 为什么建立连接是三次握手,断开连接需要四次挥手

面试官提问: 为什么 TCP 建立连接只需要三次握手,而 TCP 断开连接需要四次握手?

题目解析:

关于 TCP 建立连接三次握手的必要性,我们已经在上一章节进行了分析,这里不再赘述,这里分析下四次握手的必要性。

前置说明:TCP 是双向通信的协议,客户端可以发送和接收数据,服务器端也可以发送和接收数据,也就是全双工通信模式。

第一次挥手时,服务器端收到了客户端的 FIN 请求结束报文,但是因为应用层的进程可能还需要传输一些数据,不能立即关闭 SOCKET,所以只能先给客户端发送一个 ACK 确认报文,让客户端有 "心理准备"。之后服务器端进入 CLOSE_WAIT 状态,这个状态是为了处理最后的一些数据,等待这些数据也传输完毕之后,服务器端再发送 FIN 请求结束报文,到这里就已经有三次挥手的步骤了。最后,因为服务器端也需要感知第三次挥手的报文是否成功传输到客户端,所以客户端还需要第四次挥手的报文,来作为确认。

2.3 TIME_WAIT 状态

面试官提问: 第四次挥手之后,客户端进入的 TIME_WAIT 状态是什么含义?有什么限制?

题目解析:

在候选人成功向面试官阐述了四次挥手的过程细节以及四次的必要性之后,面试官大概率会针对 TIME_WAIT 这个状态发出提问。

我们将这个问题拆解开来,分步分析:

(1)TIME_WAIT 状态的开始时间:TCP 连接中主动关闭连接的一方(一般看作客户端)发送完最后一次挥手,主动关闭方就进入 TIME_WAIT 状态。

(2)TIME_WAIT 的持续时间:TIME_WAIT 的时间是 2*MSL(Maximum Segment Lifetime),即两个最大数据段生命周期。

(3)TIME_WAIT 为什么要持续 2*MSL 这么长的时间:

① 防止丢失报文导致异常:客户端发送的最后一个 ACK 报文可能丢失,服务器端收不到响应则会发送第三次挥手的超时重传报文,我们假设客户端没有 TIME_WAIT 状态,而是直接进入 CLOSED 状态,则会收到非法的报文段,返回一个 RST(拒绝连接)的报文,产生异常。

② 防止报文在网络中停止影响下次建立连接:MSL 表示报文在网络中的最大传输时间,等待 2*MSL 可以让网络中的所有旧报文段都失效,下一次重新三次握手时就不会收到无效的报文段。

3. 小结

本章节给大家分析了 TCP 关闭连接的过程以及常见提问,需要大家能够在白纸上画出 TCP 四次挥手的每个流程,并且重点关注 TIME_WAIT 这个状态。