TCP连接四次挥手的过程,为什么是四次?
15 分钟阅读
•
1562 字
+
1303 词
假设客户端主动调用关闭连接,发送FIN报文给服务端,并且客户端进入FIN_WAIT1状态,然后服务端收到这个报文后,read会返回EOF,并且进入CLOSE_WAIT,并发送ACK报文给客户端,服务端在这个状态还是可以发送数据的。客户端收到这个ACK后,会进入FIN_WAIT2状态。
当服务端主动调用关闭连接函数的时候,发送一个FIN报文给客户端,服务端此时进入LAST_ACK状态。
客户端收到这个FIN报文后,会返回一个ACK报文,并进入TIME_WAIT状态,这个状态等待2个MSL时间才会关闭。服务端收到这个ACK后就会进入 CLOSE状态。
为什么需要四次挥手?
因为
TCP是全双工通信,两次挥手只能释放一端到另一端的TCP连接。
并且,只有四次挥手,才能确保
双方都能接收到最后一个数据报的ACK
。如果
使用三次握手
的话,服务器在发送最后一个数据段后立即关闭连接,而客户端可能因为网络原因接收不到这个数据,那么也就无法正常关闭。
(1)四次挥手的过程
服务器收到客户端的 FIN 报文时,内核会马上回一个 ACK 应答报文,
但是服务端应用程序可能还有数据要发送,所以并不能马上发送 FIN 报文,而是将发送 FIN 报文的控制权交给服务端应用程序
:
不一定。
如果进程退出了,不管是不是正常退出,还是异常退出(如进程崩溃),内核都会发送 FIN 报文,与对方完成四次挥手。
计算机网络 - TCP 协议原理总结 | 春水煎茶 (writings.sh)
参考答案:
-
第一次挥手
:
客户端发送一个
FIN报文给服务端 ,表示自己要断开数据传送,报文中会 指定一个序列号(seq=x)。然后, 客户端进入FIN-WAIT-1状态 。 -
第二次挥手
:
服务端收到
FIN报文后 , 回复ACK报文 给客户端,且把客户端的序列号值+1,作为ACK报文的序列号(seq=x+1)。然后, 服务端进入CLOSE-WAIT(seq=x+1)状态 , 客户端进入FIN-WAIT-2状态 。 -
第三次挥手
:服务端也要断开连接时,
发送
FIN报文给客户端,且指定一个序列号(seq=y+1),随后服务端进入LAST-ACK状态 。 -
第四次挥手
:
客户端收到
FIN报文后,发出ACK报文进行应答 ,并把服务端的序列号值+1作为ACK报文序列号(seq=y+2)。 此时客户端进入TIME-WAIT状态 。 服务端在收到客户端的ACK报文后进入CLOSE状态 。 如果客户端等待2MSL没有收到回复,才关闭连接。
- 客户端主动调用关闭连接的函数,于是就会发送 FIN 报文,这个 FIN 报文代表客户端不会再发送数据了,进入 FIN_WAIT_1 状态;
- 服务端收到了 FIN 报文,然后马上回复一个 ACK 确认报文,此时服务端进入 CLOSE_WAIT 状态。在收到 FIN 报文的时候,TCP 协议栈会为 FIN 包插入一个文件结束符 EOF 到接收缓冲区中,服务端应用程序可以通过 read 调用来感知这个 FIN 包,这个 EOF 会被 放在已排队等候的其他已接收的数据之后 ,所以必须要得继续 read 接收缓冲区已接收的数据;
- 接着,当服务端在 read 数据的时候,最后自然就会读到 EOF,接着 read() 就会返回 0,这时服务端应用程序如果有数据要发送的话,就发完数据后才调用关闭连接的函数,如果服务端应用程序没有数据要发送的话,可以直接调用关闭连接的函数 ,这时服务端就会发一个 FIN 包,这个 FIN 报文代表服务端不会再发送数据了,之后处于 LAST_ACK 状态;
- 客户端接收到服务端的 FIN 包,并发送 ACK 确认包给服务端,此时客户端将进入 TIME_WAIT 状态;
- 服务端收到 ACK 确认包后,就进入了最后的 CLOSE 状态;
- 客户端经过 2MSL 时间之后,也进入 CLOSE 状态;
TCP
是全双工通信,可以双向传输数据。
任何一方都可以在数据传送结束后
发出连接释放的通知
,待对方确认后
进入半关闭状态
。 当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后才会完全关闭
TCP
连接。
因此两次挥手可以释放一端到另一端的
TCP
连接,完全释放连接一共需要四次挥手
。
只有通过四次挥手,才可以确保双方都能接收到对方的最后一个数据段的确认
,主动关闭方在发送完最后一个
ACK
后进入
TIME-WAIT
状态,这是
为了确保被动关闭方接收到最终的
ACK
,如果被动关闭方没有接收到,它可以重发
FIN
报文,主动关闭方可以再次发送
ACK
。
而如果使用三次挥手,被动关闭方可能在发送最后一个数据段后立即关闭连接,而主动关闭方可能因为网络原因接受不到这个数据段,那么也就无法正常关闭,而此时被动关闭方已经关闭连接了,也无法重传这个数据段。
为什么 TCP 挥手需要四次呢?
- 如果服务端应用程序有数据要发送的话,就发完数据后,才调用关闭连接的函数;
- 如果服务端应用程序没有数据要发送的话,可以直接调用关闭连接的函数,
FIN 报文一定得调用关闭连接的函数,才会发送吗?