一、三次握手 ------ 建立连接
目的是确认双方的收发能力正常,并同步初始序列号。
过程详解:
-
第一次握手:
-
客户端向服务器发送一个 TCP 报文段,其中:
-
标志位
SYN = 1,表示请求建立连接。 -
序列号
seq = x(x是客户端的随机初始序列号)。
-
-
发送后,客户端进入
SYN-SENT状态。
-
-
第二次握手:
-
服务器收到客户端的
SYN报文后,如果同意连接,则回复一个报文段,其中:-
标志位
SYN = 1和ACK = 1。 -
序列号
seq = y(y是服务器的随机初始序列号)。 -
确认号
ack = x + 1(表示期望收到客户端的下一个序号,同时确认了客户端的SYN)。
-
-
发送后,服务器进入
SYN-RCVD状态。
-
-
第三次握手:
-
客户端收到服务器的
SYN+ACK报文后,必须再次确认。 -
客户端发送一个报文段,其中:
-
标志位
ACK = 1。 -
序列号
seq = x + 1(第一次握手的seq+ 1)。 -
确认号
ack = y + 1(表示期望收到服务器的下一个序号,确认了服务器的SYN)。
-
-
发送后,客户端进入
ESTABLISHED(已建立连接)状态。服务器收到这个ACK后,也进入ESTABLISHED状态。
-
为什么是三次,而不是两次?
核心原因:防止已失效的连接请求报文突然到达,导致服务器资源浪费。
假设只有两次握手:客户端发送一个旧的
SYN报文(在网络中滞留很久)到达服务器,服务器误以为是一个新请求,直接回复SYN+ACK并进入连接状态。但客户端可能早已放弃,不会发送数据,导致服务器空等,浪费资源。三次握手 确保了:双方都确认了自己和对方的发送、接收能力是正常的 。服务器在收到第三次握手的
ACK后,才确认连接建立,此时客户端一定"活着"。
二、四次挥手 ------ 终止连接
目的是双方都安全、有序地关闭数据通道。由于 TCP 连接是全双工的,每个方向都必须单独关闭。
过程详解:
假设客户端主动发起关闭。
-
第一次挥手:
-
客户端发送一个 TCP 报文段,其中:
-
标志位
FIN = 1,表示客户端数据已发送完毕,请求关闭连接。 -
序列号
seq = u。
-
-
发送后,客户端进入
FIN-WAIT-1状态。
-
-
第二次挥手:
-
服务器收到
FIN报文后,立即回复一个确认报文,其中:-
标志位
ACK = 1。 -
确认号
ack = u + 1。 -
序列号
seq = v。
-
-
发送后,服务器进入
CLOSE-WAIT状态。此时,从客户端到服务器这个方向的连接就关闭了(客户端不会再发数据,但服务器可能还有数据要发送)。 -
客户端收到这个
ACK后,进入FIN-WAIT-2状态,等待服务器的FIN报文。
-
-
第三次挥手:
-
当服务器将剩余的数据发送完毕后,准备关闭连接。
-
服务器发送一个报文段,其中:
-
标志位
FIN = 1和ACK = 1(这里的ACK通常还是对第一次FIN的确认)。 -
序列号
seq = w(在半关闭期间,服务器可能又发送了数据,seq会增长)。 -
确认号
ack = u + 1。
-
-
发送后,服务器进入
LAST-ACK状态,等待客户端的最终确认。
-
-
第四次挥手:
-
客户端收到服务器的
FIN报文后,必须发送确认。 -
客户端发送一个报文段,其中:
-
标志位
ACK = 1。 -
序列号
seq = u + 1(因为第一次挥手后,客户端没有发送数据)。 -
确认号
ack = w + 1。
-
-
发送后,客户端进入
TIME-WAIT状态,等待 2MSL(最长报文段寿命的两倍)时间 后,才进入CLOSED状态。 -
服务器收到这个最终的
ACK后,立即进入CLOSED状态。
-
为什么是四次?
因为连接是全双工的,关闭需要两个独立的方向。当一方发送
FIN,只表示它没有数据要发送了,但还可以接收数据。所以,收到FIN后,另一方先回复ACK(表示"我知道你要关了"),然后等自己这边数据也发完了,再发送自己的FIN。这就比握手多了一个来回。
为什么客户端需要 TIME-WAIT 状态?等待 2MSL 是为什么?
主要原因有两个:
确保最后一个
ACK能到达服务器 :如果服务器没有收到第四次挥手的ACK,会超时重传第三次挥手的FIN报文。客户端在TIME-WAIT状态下可以收到这个重传的FIN,然后重传ACK,保证连接能可靠关闭。让旧连接的报文在网络中消散:等待 2MSL 时间,可以确保本次连接所产生的所有报文都从网络中消失,避免影响后续建立的新连接(防止序列号混淆)。
图解总结
三次握手:
客户端:SYN, seq=x -> 服务器
客户端: <- 服务器:SYN+ACK, seq=y, ack=x+1
客户端:ACK, seq=x+1, ack=y+1 -> 服务器
连接建立成功!
四次挥手(客户端主动关闭):
客户端:FIN, seq=u -> 服务器
客户端: <- 服务器:ACK, ack=u+1
(等待服务器发送剩余数据...)
客户端: <- 服务器:FIN+ACK, seq=w, ack=u+1
客户端:ACK, ack=w+1 -> 服务器
(客户端等待 2MSL 后关闭)
连接完全关闭!
一、三次握手 ------ 打电话建立连接
想象你要给朋友小美打电话,建立通话的过程就是"三次握手":
-
第一次握手(你打过去)
你:"喂,小美,听得到吗?"
(你发送SYN,等待她确认) -
第二次握手(她回答)
小美:"听得到!你听得到我吗?"
(她收到你的呼叫并确认,同时她也发起询问,相当于SYN+ACK) -
第三次握手(你确认)
你:"我也听得到你,那我们开始聊吧!"
(你确认了她的询问,连接建立成功)
为什么不是两次?
如果是两次:
你问:"听得到吗?"
小美回答:"听得到!"
然后就以为通话通了。
但万一小美的回答你没听到呢?她以为通了就开始说话,其实你这边根本没准备好。所以需要第三次确认,确保双方都知道"我们能正常通话了"。
二、四次挥手 ------ 挂电话终止连接
现在通话结束,要挂电话了。因为是全双工(双方都能说能听),挂断需要两个方向都关闭:
-
第一次挥手(你说完了)
你:"我要说的话都说完了,准备挂电话了。"
(发送FIN,表示你不再发送数据了,但你还可以听她说话) -
第二次挥手(她确认)
小美:"好的,我知道了。"
(她确认收到你的挂断请求,但这只是针对"你不说了"的确认,她可能还有话要说) -
第三次挥手(她说完了)
小美:"我也说完了,我也准备挂电话了。"
(她也发送FIN,表示她这边也说完了) -
第四次挥手(你最终确认)
你:"好的,那挂了吧!"
(你确认她的挂断请求,双方正式结束通话)
为什么是四次?
因为挂电话需要双方都说"我说完了"。
你说完 → 她确认 → 她说完 → 你确认
这比建立连接多了一步。
为什么你最后要等一会儿(TIME-WAIT)?
你说了"好的,那挂了吧!"之后,不会立刻挂断,而是等2秒,以防小美没听到你的最后一句。如果小美没听到,她会再说一次"我要挂了",你就能重说一次"好的,挂了吧",确保双方都能正确结束。
一句话总结
-
三次握手 :
A:在吗? → B:在的,你在吗? → A:我也在!→ 建立可靠连接
-
四次挥手 :
A:我说完了 → B:好的 → B:我也说完了 → A:好的→ 双方礼貌道别,安全断开