TCP三次握手
在双方开始正式传输 HTTP 数据之前,必须先通过三次握手来同步双方的序列号(seq)和确认号(ack),并协商 TCP 窗口大小。通俗地说,就是为了**确认双方的“发送”和“接收”能力都是正常的**。
#status / growing
#type / concept
#resource / typescript
[!info] related notes
TCP三次握手
在双方开始正式传输 HTTP 数据之前,必须先通过三次握手来同步双方的序列号(seq)和确认号(ack),并协商 TCP 窗口大小。通俗地说,就是为了确认双方的“发送”和“接收”能力都是正常的。
我为您拆解一下这三次握手的具体过程:
1. 第一次握手(客户端 -> 服务端)
- 动作:客户端向服务端发送一个带有
SYN=1(同步序列编号)标志位的数据包,并随机生成一个初始序列号seq = x。发送后,客户端进入SYN_SENT状态。 - 潜台词:“服务端你好,我想跟你建立连接,你能听到我说话吗?”
2. 第二次握手(服务端 -> 客户端)
- 动作:服务端收到这个 SYN 数据包后,知道客户端要建立连接。于是它向客户端发送一个带有
SYN=1和ACK=1(确认标志)的数据包。其中确认号ack = x + 1(表示收到了客户端的序列号),同时服务端也随机生成自己的初始序列号seq = y。发送后,服务端进入SYN_RCVD状态。 - 潜台词:“我听到了!我也准备好跟你建立连接了,你能听到我说话吗?”
- (注:此时服务端确认了客户端的发送能力和自己的接收能力是正常的)
3. 第三次握手(客户端 -> 服务端)
- 动作:客户端收到服务端的 SYN+ACK 包后,知道服务端同意连接了。于是它向服务端发送一个带有
ACK=1标志的确认包。确认号ack = y + 1,序列号seq = x + 1。发送后,客户端进入ESTABLISHED(已连接)状态;服务端收到这个包后,也进入ESTABLISHED状态。 - 潜台词:“我也听到了!我们的通信没问题,准备开始传数据吧。”
- (注:此时客户端确认了服务端的发送能力和自己的接收能力,服务端也确认了客户端的接收能力正常)
面试高频追问防守:为什么必须是三次,两次不行吗?
如果只握手两次,会存在一个致命的漏洞:防止历史失效的连接请求报文段突然又传送到了服务端,导致资源浪费。
假设客户端发出的第一个 SYN 包在网络节点中滞留了,客户端等不到响应,超时后又发了一个新的 SYN 包,完成了两次握手并传完数据断开了。 此时,那个滞留的“旧 SYN 包”突然到达了服务端。如果是“两次握手”,服务端只要收到 SYN 就会直接建立连接并分配资源,然后一直傻等着客户端发数据。但客户端现在根本没打算发数据,服务端的端口和内存资源就被白白占用(这也叫 SYN 泛洪攻击的原理基础)。
而在“三次握手”机制下,服务端收到旧的 SYN 包回复 SYN+ACK 后,客户端一看确认号不对(是过期的),就会发一个 RST 报文让服务端中止连接,从而完美避开这个问题。