TCP 三次握手和四次挥手(传输层)
为了准确无误地把数据送达目标处,TCP 协议采用了三次握手策略。
建立连接 - TCP 三次握手
在 TCP 协议中,建立连接的过程通过三次握手来实现。这一过程确保了通信双方的连接可靠性,并能够正确地同步序列号等关键信息。
三次握手过程
- 第一次握手:客户端发送带有 SYN 标志的数据包,序列号为
x
,请求建立连接。客户端进入 SYN_SEND 状态,等待服务器的确认。 - 第二次握手:服务器收到客户端的 SYN 包后,发送一个包含 SYN+ACK 标志的数据包,序列号为
y
,确认号为x+1
。服务器进入 SYN_RECV 状态,等待客户端确认。 - 第三次握手:客户端收到服务器的 SYN+ACK 包后,发送一个 ACK 标志的数据包,确认号为
y+1
。此时,客户端和服务器都进入 ESTABLISHED 状态,连接成功建立。
一旦三次握手完成,客户端和服务器就可以开始数据传输。
半连接队列和全连接队列
在 TCP 三次握手过程中,操作系统维护两个队列来管理连接请求:
- 半连接队列:也称为 SYN 队列。客户端发出的 SYN 请求到达服务器时,服务器将该请求放入半连接队列。此时连接还未完全建立,因为服务端还没有收到客户端的 ACK 响应。
- 全连接队列:也称为 Accept 队列。当客户端确认收到服务器的 SYN+ACK 后,三次握手完成,连接进入全连接队列。如果客户端未在规定时间内响应 ACK,服务器会重发 SYN+ACK,直到连接成功或达到最大重传次数。
为什么要三次握手?
三次握手的主要目的是确保双方能够可靠地发送和接收数据:
- 第一次握手:客户端确认自己发送正常,服务器确认能够接收客户端的数据。
- 第二次握手:客户端确认自己接收正常,服务器确认自己发送正常,客户端确认自己可以接收数据。
- 第三次握手:双方确认可以双向通信,并开始数据传输。
通过三次握手,确保了通信的可靠性和同步,避免了连接建立的过程中产生不必要的误解。
为什么要返回 SYN 和 ACK?
在 TCP 的三次握手中,服务端返回的 SYN 和 ACK 的作用分别是:
- ACK:确认客户端发送的 SYN 数据包,表明从客户端到服务端的通信链路正常。
- SYN:标志着服务器希望与客户端建立连接,并确认服务端到客户端的通信链路也是正常的。
这样可以确保双方的连接准备好,可以开始传输数据。
三次握手是否可以携带数据?
根据 RFC 793 标准,TCP 三次握手的第三次握手是可以携带数据的。虽然三次握手主要是用于建立连接的,但客户端在发送第三次握手时(即发送 ACK 包时),可以携带数据。TCP 允许在建立连接的同时开始传输应用数据,节省了时间。
如果第三次握手的 ACK 包丢失,但客户端已经开始发送带数据的包,服务端会根据该包中包含的 ACK 标志来确认连接已建立,并继续数据传输。
断开连接 - TCP 四次挥手
与连接建立的三次握手不同,断开连接需要四次挥手。这是因为 TCP 是全双工协议,数据可以从任一方向传输,因此每一方都需要独立地关闭连接。
四次挥手过程
- 第一次挥手:客户端发送一个 FIN 数据包(SEQ=x),请求关闭客户端到服务端的连接。客户端进入 FIN-WAIT-1 状态。
- 第二次挥手:服务端收到客户端的 FIN 后,发送一个 ACK 数据包(ACK=x+1),确认关闭客户端到服务端的连接。服务端进入 CLOSE-WAIT 状态,客户端进入 FIN-WAIT-2 状态。
- 第三次挥手:服务端发送一个 FIN 数据包(SEQ=y),请求关闭服务端到客户端的连接。服务端进入 LAST-ACK 状态。
- 第四次挥手:客户端确认收到服务端的 FIN 后,发送一个 ACK 数据包(ACK=y+1)。此时客户端进入 TIME-WAIT 状态,等待 2MSL(最大报文生存时间),确保服务端收到了 ACK 数据包。服务端收到客户端的 ACK 后进入 CLOSE 状态,连接完全关闭。
为什么要四次挥手?
TCP 使用四次挥手断开连接的原因是因为每一方都可以独立地关闭连接:
- 第一次挥手:客户端关闭从客户端到服务端的连接,告知服务端不再有数据发送。
- 第二次挥手:服务端确认收到关闭请求,但可能还会继续向客户端发送数据。
- 第三次挥手:服务端关闭从服务端到客户端的连接,告知客户端没有数据要发送。
- 第四次挥手:客户端确认服务端关闭连接后,自己也关闭连接。
为什么不能合并成三次挥手?
服务端在收到客户端的 FIN 后,可能仍然有未发送完的数据。如果将 ACK 和 FIN 合并为一个数据包,会导致服务端还在发送数据时关闭连接,这会影响数据的传输。因此,必须分两步:先发送 ACK,确认客户端的断开请求;等服务端数据发送完后,再发送 FIN 请求,断开服务端到客户端的连接。
如果第二次挥手时服务端的 ACK 没有送达客户端,会怎样?
如果第二次挥手时客户端没有收到服务端的 ACK,客户端会重新发送 FIN 数据包,确保服务端收到断开请求。这也是 TCP 可靠性的一部分,通过重传机制确保连接正确关闭。
为什么第四次挥手客户端需要等待 2MSL?
在第四次挥手时,客户端发送的 ACK 数据包可能会丢失。如果客户端没有收到服务端的 FIN 响应,它会重发 ACK,并再次等待。如果在 2MSL 的时间内没有接收到服务端的 FIN,则客户端确认服务端已关闭连接,随后完成连接的关闭。
MSL (Maximum Segment Lifetime):指一个数据包在网络中存在的最大时间。2MSL 确保了客户端能够接收到服务端的 FIN 数据包或重发的 ACK,以确保连接的完全关闭。