TCP三次握手

107 阅读4分钟

概念

TCP 是通过三次握手建立双向连接的可靠传输协议,其本质是交换携带控制信息的 TCP 段

过程

建立TCP连接:

第一次握手, 客户端向服务器发送一个SYN段(SYN=1, seq=ISN_C),请求同步。(同步意味着连接,这条消息是询问:你好,服务器,你能为我打开一个连接吗)

第二次握手,服务器回复一个SYN-ACK段(SYN=1, ACK=1, seq=ISN_S, ack=ISN_C+1)。表示同步和确认。(服务器确认以及同意了客户端的连接请求,并要求客户端打开连接)

第三次握手,客户端回复一个ACK段(ACK=1, seq=ISN_C+1, ack=ISN_S+1)(表示客户端也收到了服务器发来的连接请求)

双方均收到对端的 SYN 并回复 ACK 后,进入 ESTABLISHED 状态,即他们之间就建立了连接......

image.png

前文使用的 SYN段、SYN-ACK段、ACK段 都是 TCP段 的子类。
为保持术语层级清晰,后文将统一使用 TCP段 作为基础术语。

SYN

可以把SYN和ACK看作信号灯,设置初始序列号的时候,SYN的值就会为1,否则为0

ACK

ACK=1用来表示收到有效数据,“我已收到该序号前的所有字节”

seq是干什么的呢?是用来给TCP段确认顺序

第一次握手时,发送方的第一个TCP段会随机生成一个初始序列号即ISN,而seq的值将会在随机生成的ISN的值的基础上加一,例如客户端发的第一个TCP段的seq是1000,那么客户端发的第二个的TCP段的seq将是1001

所以,图内 第一次握手,客户端发送自己的第一个TCP段,seq = 1000 (ISN_C)

第二次握手,服务器发送自己的第一个TCP段,seq = 5000 (ISN_S), ack = 1001 (ISN_C + 1) 第三次握手,客户端发送自己的第二个TCP段,seq = 1001 (ISN_C + 1), ack = 5001 (ISN_S + 1)

ack是干什么的呢?是用来告诉对方下一个应该接受的TCP段

再来回顾图中内容,第一次握手客户端发送给服务器的是序列号为1000的TCP段,那么服务器下一次发送的应该是序列号为1001的TCP段,

所以第二次握手时,服务器在ack的值里提醒了客户端,即ack=1001,它告诉客户端你这次发的是1000,下次我收到的应该是序列号为1001的TCP段

服务器发给客户端也是同理

seq和ack都保证了双方不会漏收数据

好处

  • 三次握手可以验证当时握手的双方都有接受和发送的能力

  • SYN报文里的初始序列号(seq)可以用来区分新旧报文,避免网络延迟导致历史连接混乱(比如重复发送的上一次已经关闭的TCP连接发送的SYN报文,被误认为新的SYN报文)

  • 握手双方交换 ISN_C 和 ISN_S,保证后续数据包的有序传输

  • 防止资源耗尽,结合 SYN Cookie 机制抵御 SYN洪水攻击

扩展

SYN Cookie工作流程
  1. 收到SYN → 计算哈希值 H = F(源IP+端口+目标IP+端口+密钥)
  2. 发送SYN-ACK,其中包含的 ISN_S = (H << 24) + 时间戳
  3. 收到ACK → 验证确认号 ack_num - 1 == H ? 分配资源 : 丢弃
SYN洪水攻击

前提:服务器收到SYN报文(第一次握手请求),回复SYN-ACK后会进入半开连接(SYN_RCVD) 状态,等待第三次握手,而半开连接会占用内核资源(如连接队列、内存等)

原理:攻击者伪造大量虚假IP地址,向目标服务器发送海量SYN报文,服务器收到SYN报文并回复SYN-ACK后,服务器进入半开连接(SYN_RCVD) 状态,而虚假IP不会回复第三次握手的ACK报文,服务器会持续等待直到超时

影响:导致新的合法SYN请求被拒绝;系统资源被无效连接占满;正常用户无法建立TCP连接