文章目录
一、关闭连接的过程
-
第一次挥手:客户端发送一个
FIN
报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1
状态
由浏览器发起的,发送给服务器,我请求报文发送完了,你准备关闭吧. -
第二次挥手:服务端收到
FIN
之后,会发送ACK
报文,且把客户端的序列号值+1
作为ACK
报文的序列号值,表明已经收到客户端的报文了,此时服务端处于CLOSE_WAIT
状态
由服务器发起的,告诉浏览器,我请求报文接受完了,我准备关闭了,你也准备吧 -
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发送FIN
报文,且指定一个序列号。此时服务端处于
LAST_ACK`的状态
由服务器发起,告诉浏览器,我响应报文发送完了,你准备关闭吧 -
第四次挥手:客户端收到
FIN
报文,发送ACK
确认报文。需要过一阵子以确保服务端收到自己的ACK
报文之后才会进入CLOSED
状态,服务端收到ACK
报文之后,就处于关闭连接了,处于CLOSED
状态。
由浏览器发起,告诉服务器,我响应报文接受完了,我准备关闭了,你也准备吧
二、四次挥手相关问题
1.为什么开启TCP链接需要三次握手而关闭TCP连接需要四次?
当建立连接时服务端收到客户端的SYN
连接请求报文后,可以直接发送SYN+ACK
报文。其中ACK
报文是用来应答的,SYN报
文是用来同步的。
但是关闭连接时,当服务端收到FIN
报文时,很可能并不会立即关闭连接,所以只能先回复一个ACK
报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN
报文,因此不能一起发送。故需要四次挥手。
2.为什么客户端发送ACK之后不直接关闭,而是要等一阵子才关闭?
客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1
),客户端进入TIME_WAIT
(时间等待)状态。此时TCP
未释放掉,需要经过时间等待计时器设置的时间2MSL
(最大报文生存时间)后,客户端才进入CLOSED
状态。
如果不等待,客户端直接跑路,当服务端还有很多数据包要给客户端发,且还在路上的时候,若客户端的端口此时刚好被新的应用占用,那么就接收到了无用数据包,造成数据包混乱。
3.为什么TIME_WAIT状态需要经过2MSL(最大报文生存时间)才能返回到CLOSE状态?
理论上,四个报文都发送完毕,就可以直接进入CLOSE
状态了,但是可能网络是不可靠的,有可能最后一个ACK
丢失。所以TIME_WAIT
状态就是用来重发可能丢失的ACK
报文。Server
如果没有收到ACK
,将不断重复发送FIN
片段。所以Client
不能立即关闭,它必须确认Server
接收到了该ACK
。
Client
会在发送出ACK
之后进入到TIME_WAIT
状态。Client
会设置一个计时器,等待2MSL
的时间。如果在该时间内再次收到FIN
,那么Client
会重发ACK
并再次等待2MSL
。
所谓的2MSL
是两倍的 MSL(Maximum Segment Lifetime)
。
MSL
指一个片段在网络中最大的存活时间,2MSL
就是一个发送和一个回复所需的最大时间。如果直到2MSL
,Client
都没有再次收到FIN
,那么Client
推断ACK
已经被成功接收,则结束TCP
连接。
2MSL
,即:1 个 MSL
确保四次挥手中主动关闭方最后的 ACK
报文最终能达到对端; 1 个 MSL
确保如果对端没有收到 ACK
重传的FIN
报文可以到达。