四次挥手是客户端和服务端断开连接的途径。
一.四次挥手的过程:
第一次挥手:
客户端打算关闭连接,此时会发送⼀个 TCP ⾸部 FIN 标志位被置为 1 的报⽂,也即 FIN 报⽂,之后客户端进⼊ FIN_WAIT_1 状态。
第二次挥手:
服务端收到该报⽂后,就向客户端发送 ACK 应答报⽂,接着服务端进⼊ CLOSED_WAIT 状态。
第三次挥手:
客户端收到服务端的 ACK 应答报⽂后,之后进⼊ FIN_WAIT_2 状态。但此时服务端可能还有一些数据未处理完。等待服务端处理完数据后,也向客户端发送 FIN 报⽂,之后服务端进⼊ LAST_ACK 状态。
第四次挥手:
客户端收到服务端的 FIN 报⽂后,回⼀个 ACK 应答报⽂,之后进⼊ TIME_WAIT 状态
服务端收到了 ACK 应答报⽂后,就进⼊了 CLOSED 状态,⾄此服务端已经完成连接的关闭。
客户端在经过 2MSL ⼀段时间后,⾃动进⼊ CLOSED 状态,⾄此客户端也完成连接的关闭。
二.为什么要进行四次挥手?
我们一步一步来分析,首先第一次挥手一定是不能省略的,否则服务端不知道客户端要断开连接。
再来看第二次挥手和第三次挥手,关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。同时此时服务端也很有可能还要处理一些数据,而服务端的数据处理不完是不可能直接给客户端相应可以关闭连接的报文的,这会导致数据丢失。因此,服务端必须额外发送一次报文,用于通知客户端自己的数据已经处理完毕。
那么能不能在服务端数据处理完之后直接回复给客户端FIN+ACK呢?也是不行的。因为如果要处理的数据太多,客户端会长时间得不到回应。这可能会导致客户端认为自己的数据包丢失。然后客户端会重发FIN报文,导致资源浪费。
因此FIN和ACK是必要分两次与客户端进行挥手的
那么能不能省去最后一步挥手呢?也是不行的。如果服务端在响应ACK后直接关闭的话,如果最后一次挥手的数据包丢失,那么将导致客户端无法关闭。
由上述分析,无论如何,都要进行四次挥手。
三.为什么要第四次挥手时,客户端要等待2MSL?
首先来解释一下,MSL 为Maximum Segment Lifetime,即报⽂最⼤⽣存时间,它是任何报⽂在⽹络上存在的最⻓时间,超过这个时 间报⽂将被丢弃。
那么为什么要等待2个MSL呢?
先来看下图:
试想一下,假如在四次挥手的过程中有一个数据包因为网络原因被阻塞。如果没有TIME_WAIT这个阶段,直接关闭了连接。在客户端和服务端再次建立连接时,之前被阻塞的数据包可能再次被接收到。这就是客户端需要TIME_WAIT的原因,而之所以设置成2MSL是为了让客户端到服务端和服务端到客户端这两个方向上的报文都被丢弃。
还有一个原因,就是要保证连接可以正确地关闭。因为一旦最后一次挥手丢包,如果没有TIME_WAIT阶段,客户端将直接关闭,这将使得报文无法重发,服务端将无法关闭,一直处于LAST_ACK状态,使得客户端和服务端之间无法建立连接。
TIME_WAIT的时间在Linux中默认为30s,可自行设置,但不可设置得过长,因为TIME_WAIT过长将导致内存资源和端口资源的占用过大。