好的,这是一个关于 TCP 三次握手 的清晰、详细的解释。
核心目的
TCP 三次握手的主要目的是建立一个可靠的、全双工的连接,并在双方之间同步初始序列号。它确保通信双方都具备发送和接收数据的能力。
握手过程
假设客户端(Client)想要与服务器(Server)建立连接。
第一步:SYN
-
客户端 发送一个 TCP 数据包,其中:
-
标志位
SYN = 1:表示这是一个"同步"请求,希望建立连接。 -
序列号
seq = x:x是客户端随机选择的初始序列号。
-
-
此时,客户端进入 SYN-SENT 状态。
第二步:SYN + ACK
-
服务器 收到客户端的 SYN 包后,如果同意连接,则会回复一个数据包,其中包含:
-
标志位
SYN = 1和ACK = 1:SYN=1表示服务器也在同步自己的序列号;ACK=1表示确认号字段有效。 -
序列号
seq = y:y是服务器随机选择的初始序列号。 -
确认号
ack = x + 1:这表示"我(服务器)已经收到了你的序列号为x的包,下一个我期望收到序列号为x+1的包"。这是对客户端SYN的确认。
-
-
此时,服务器进入 SYN-RECEIVED 状态。
第三步:ACK
-
客户端 收到服务器的
SYN-ACK包后,会再次发送一个确认包,其中包含:-
标志位
ACK = 1:表示这是一个确认包。 -
序列号
seq = x + 1:因为客户端的第一个SYN包消耗了一个序列号x,所以下一个包的序列号就是x+1。 -
确认号
ack = y + 1:表示"我(客户端)已经收到了你的序列号为y的包,下一个我期望收到序列号为y+1的包"。这是对服务器SYN的确认。
-
-
客户端发送完这个包后,进入 ESTABLISHED 状态。
-
服务器 收到这个
ACK包后,也进入 ESTABLISHED 状态。 -
至此,连接建立成功,双方可以开始传输数据。
为什么是"三次",而不是两次或四次?
这是一个经典问题,关键在于 可靠性和效率的平衡。
-
防止已失效的连接请求报文造成混淆(主要理由)
-
想象一个场景:客户端发送了一个
SYN请求,但由于网络延迟,这个包很久才到达服务器。客户端等不到回复,会重发一个新的SYN并成功建立了连接、完成了通信、关闭了连接。 -
此时,那个迟到的、旧的
SYN包终于到达了服务器。如果只需要两次握手(服务器回复SYN-ACK后就认为连接已建立),服务器就会单方面建立一个无用的连接,并等待客户端发送数据,造成资源浪费。 -
三次握手 机制下,服务器发送
SYN-ACK后,必须等待客户端的最终ACK。对于那个迟到的旧请求,客户端不会回复ACK(因为它没有发起这个连接),因此服务器在超时后会自动关闭这个半连接,避免了资源浪费。
-
-
双方确认双方的发送和接收能力都正常
-
第一次握手:服务器确认"客户端的发送能力、自己的接收能力"正常。
-
第二次握手:客户端确认"自己的发送和接收能力、服务器的发送和接收能力"都正常。
-
第三次握手:服务器确认"客户端的接收能力、自己的发送能力"正常。
-
经过三次交换,双方都确信自己和对端具备完整的通信能力。
-
-
同步初始序列号
- TCP 依靠序列号来保证数据的有序性和可靠性。三次握手确保了双方都明确知道了对方的初始序列号,为后续可靠传输打下了基础。
四次握手 没有必要,因为可以将服务器的 SYN 和对客户端 SYN 的 ACK 合并成一个包发送,提高了效率。
状态变化总结
text
复制
下载
客户端:CLOSED -> SYN-SENT -> ESTABLISHED
服务器:CLOSED -> LISTEN -> SYN-RECEIVED -> ESTABLISHED
类比(打电话)
-
第一次握手 :A 打电话给 B,说:"喂,你好,能听到吗?" (
SYN) -
第二次握手 :B 听到后,回答:"我能听到,你呢?" (
SYN-ACK) -
第三次握手 :A 听到 B 的回答,说:"我也能听到。" (
ACK) -
开始通话:然后双方开始正式交谈(传输数据)。
相关问题:SYN 洪水攻击
攻击者疯狂地发送第一次握手(SYN)包,但不完成第三次握手。服务器会为每个半连接分配资源并等待,直到资源耗尽,无法为正常用户服务。防御方法包括 SYN Cookie 等。
如何查看?
在 Linux/Unix 系统中,可以使用 netstat 或 ss 命令查看 TCP 连接状态。在抓包工具如 Wireshark 或 tcpdump 中,可以清晰地看到 SYN, SYN-ACK, ACK 这三个包的交换过程。
总结:TCP 三次握手是互联网可靠通信的基石,它用最小的代价(三次交互)解决了在不可靠网络上建立可靠连接的根本问题。