TCP 三次握手和四次挥手
建立连接-三次握手
什么是三次握手?
简单来说:
- 客户端向服务器发送 SYN 报文,请求建立连接。
- 服务器收到 SYN 报文后,回复一个 SYN+ACK 的报文,表示同意建立连接。
- 客户端收到 SYN+ACK 报文后,再回复一个 ACK 报文,表示确认连接已经建立。
SYN – Synchronize 连接信号;ACK – Acknowledgment 确认信号
建立一个 TCP 连接需要“三次握手”,缺一不可:
- 一次握手:
- 客户端发送带有 SYN(SEQ=x)标志的数据包 -> 服务端,
- 然后客户端进入 SYN_SEND 状态,等待服务器的确认;
- 二次握手:
- 服务端发送带有 SYN+ACK(SEQ=y,ACK=x+1) 标志的数据包 –> 客户端,
- 然后服务端进入 SYN_RECV 状态
- 三次握手:
- 客户端发送带有 ACK(ACK=y+1) 标志的数据包 –> 服务端,
- 然后客户端和服务器端都进入 ESTABLISHED(established) 状态,完成 TCP 三次握手。
当建立了 3 次握手之后,客户端和服务端就可以传输数据了。
具体如下图所示:
为什么要三次握手?
三次握手的主要目的是:确保客户端和服务器之间建立了可靠的连接,同时避免因重复的连接请求造成网络资源的浪费。
- 第一次握手:
- Client 什么都不能确认;
- Server 确认了对方发送正常,自己接收正常
- 第二次握手:
- Client 确认了:自己发送、接收正常,对方发送、接收正常;
- Server 确认了:对方发送正常,自己接收正常
- 第三次握手:
- Client 确认了:自己发送、接收正常,对方发送、接收正常;
- Server 确认了:自己发送、接收正常,对方发送、接收正常
TCP 为什么是三次握手,而不是两次或四次?
因为,三次握手是为了确保连接的可靠性和避免网络资源的浪费。而两次握手会存在上述的问题,四次握手则会增加不必要的开销,所以三次握手是一种较为合理的选择。
第 2 次握手传回了 ACK,为什么还要传回 SYN?
服务端传回发送端所发送的 ACK 是为了告诉客户端:“我接收到的信息确实就是你所发送的信号了”,这表明从客户端到服务端的通信是正常的。
回传 SYN 则是为了建立并确认从服务端到客户端的通信。
什么是 SYN ?
SYN 同步序列编号(Synchronize Sequence Numbers) 是 TCP/IP 建立连接时使用的握手信号。在客户机和服务器之间建立正常的 TCP 网络连接时,客户机首先发出一个 SYN 消息,服务器使用 SYN-ACK 应答表示接收到了这个消息,最后客户机再以 ACK(Acknowledgement)消息响应。这样在客户机和服务器之间才能建立起可靠的 TCP 连接,数据才可以在客户机和服务器之间传递。
断开连接-四次挥手
什么是四次挥手?
简单来说:
- 客户端向服务器发送 FIN 报文,请求关闭连接。
- 服务器收到 FIN 报文后,回复一个 ACK 报文,确认已经收到客户端的请求。
- 服务器再向客户端发送一个 FIN 报文,表示服务器也准备关闭连接。
- 客户端收到服务器的 FIN 报文后,回复一个 ACK 报文,确认已经收到服务器的请求,并关闭连接。
具体如下图所示:
断开一个 TCP 连接则需要“四次挥手”,缺一不可:
-
第一次挥手:
-
客户端发送一个 FIN(SEQ=x) 标志的数据包->服务端,用来关闭客户端到服务器的数据传送。
-
然后,客户端进入 FIN-WAIT-1 状态。
-
-
第二次挥手:
- 服务器收到这个 FIN(SEQ=X)标志的数据包,它发送一个 ACK(ACK=x+1)标志的数据包 -> 客户端。
- 然后,此时服务端进入 CLOSE-WAIT 状态,客户端进入 FIN-WAIT-2 状态。
-
第三次挥手:
- 服务端关闭与客户端的连接并发送一个 FIN(SEQ=y) 标志的数据包 -> 客户端,请求关闭连接,
- 然后,服务端进入 LAST-ACK 状态。
-
第四次挥手:
- 客户端发送 ACK (ACK=y+1) 标志的数据包 -> 服务端并且进入 TIME-WAIT 状态,
- 服务端在收到 ACK (ACK=y+1) 标志的数据包后进入 CLOSE 状态。
- 此时,如果客户端等待 2MSL 后依然没有收到回复,就证明服务端已正常关闭,随后,客户端也可以关闭连接了。
只要四次挥手没有结束,客户端和服务端就可以继续传输数据!
为什么要四次挥手?
TCP四次挥手的主要目的是:确保客户端和服务器之间的连接能够正常关闭,并且避免因为未处理完的数据包而造成数据的丢失和不完整。
即:为了确保连接的正常关闭和数据的完整性
为什么不能把服务器发送的 ACK 和 FIN 合并起来,变成三次挥手?
因为服务器收到客户端断开连接的请求时,可能还有一些数据没有发完,这时先回复 ACK,表示接收到了断开连接的请求。等到数据发完之后再发 FIN,断开服务器到客户端的数据传送。
ACK 的作用是: 确认收到对方发送的数据包,
而 FIN 的作用是: 请求关闭连接。
如果第二次挥手时服务器的 ACK 没有送达客户端,会怎样?
客户端没有收到 ACK 确认,会重新发送 FIN 请求。
为什么第四次挥手客户端需要等待 2*MSL(报文段最长寿命)时间后才进入 CLOSED 状态?
因为第四次挥手时,客户端发送给服务器的 ACK 有可能会丢失。
如果服务端因为某些原因而没有收到 ACK 的话,服务端就会重发 FIN,
如果客户端在 2*MSL 的时间内收到了 FIN,就会重新发送 ACK 并再次等待 2MSL,防止 Server 没有收到 ACK 而不断重发 FIN。
假设客户端在发送 ACK 之后立即进入 CLOSED 状态(即关闭连接),同时 服务端没有接收到客户端的 ACK 确认,就会一直重发 FIN – 请求关闭连接。
什么是 MSL?
MSL(Maximum Segment Lifetime): 一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间。如果直到 2MSL,Client 都没有再次收到 FIN,那么 Client 推断 ACK 已经被成功接收,则结束 TCP 连接。
imum Segment Lifetime)**: 一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间。如果直到 2MSL,Client 都没有再次收到 FIN,那么 Client 推断 ACK 已经被成功接收,则结束 TCP 连接。
学习参考
- TCP 三次握手和四次挥手(传输层) | JavaGuide(Java面试 + 学习指南)