TCP三次握手总结

1.概述

TCP是面向连接的可靠传输协议,在数据传输前,通信双方必须通过三次握手建立连接。其核心作用是同步序列号、协商参数(如MSS、窗口缩放因子),并确认双方具备收发能力

2.目的

  • 确保双方都能发送和接收数据(全双工通信)。

  • 交换初始序列号(ISN,Initial Sequence Number),为后续可靠传输(如确认、重传)奠定基础。

  • 协商可选参数(如最大报文段长度MSS、窗口缩放因子、选择性确认SACK等)。

3.详细过程

  • 服务器通过listen()进入LISTEN状态,等待连接。

  • 客户端通过connect()发起连接。

步骤

握手 方向 报文内容 发送后状态
第一次 客户端 → 服务器 SYN=1seq=x(x为随机数) 客户端:SYN-SENT
第二次 服务器 → 客户端 SYN=1ACK=1seq=y(y为随机数),ack=x+1 服务器:SYN-RCVD
第三次 客户端 → 服务器 ACK=1seq=x+1ack=y+1(可携带数据) 客户端:ESTABLISHED
服务器收到后:ESTABLISHED
sequenceDiagram participant C as 客户端 participant S as 服务器 Note over C: CLOSED Note over S: LISTEN C->>S: SYN (seq = x) Note over C: SYN-SENT S->>C: SYN-ACK (seq=y, ack=x+1) Note over S: SYN-RCVD C->>S: ACK (ack = y+1) Note over C: ESTABLISHED Note over S: ESTABLISHED

4. 关键字段与标志位

  • SYN:同步序列号,在握手阶段用于建立连接,消耗一个序列号。
  • ACK:确认号有效,除第一次握手外,后续报文均需设置。
  • seq(序列号):本报文段数据的第一个字节的序号。初始值(ISN)为随机数。
  • ack(确认号):期望收到对方下一个报文段数据的第一个字节的序号,且表示之前序号的数据已成功接收。

5. 状态转换(简化)

  • 客户端CLOSEDSYN-SENTESTABLISHED
  • 服务器CLOSEDLISTENSYN-RCVDESTABLISHED

6. 为什么必须是三次握手?

两次握手的问题

如果只有两次握手,服务器在收到客户端的SYN后即进入ESTABLISHED,但此时客户端可能并未准备好(例如客户端发送的SYN因网络延迟重传,后来才到达服务器),导致服务器资源被浪费(建立无效连接)。

经典场景:客户端发送的第一个SYN在网络中滞留,超时重传后建立连接并关闭。滞留的SYN随后到达服务器,服务器误以为是新连接,回复SYN-ACK并进入ESTABLISHED,但客户端已关闭,导致服务器一直等待数据(半开连接),浪费资源。

四次握手的不足

四次握手理论上可行,但效率低。将第二次握手的SYN和ACK合并为一个报文,可以减少一次交互,提高建立速度。因此三次握手是最优解。

7. 常见问题与扩展

Q1:握手过程中丢包怎么办?

  • 第一次握手丢包:客户端超时重传SYN(重传次数可配置,通常为5次左右)。
  • 第二次握手丢包:客户端收不到SYN-ACK,会超时重传SYN;服务器已发送SYN-ACK,等待第三次ACK,若超时未收到,服务器重传SYN-ACK(次数有限)。
  • 第三次握手丢包:服务器收不到ACK,重传SYN-ACK;客户端收到重复的SYN-ACK后,会重新发送ACK(或忽略,视实现而定)。若重传多次仍无响应,服务器释放半连接资源。

Q2:初始序列号(ISN)为什么是随机的?

  • 防止旧连接的数据包被误认为是新连接的包(避免“历史连接干扰”)。
  • 提高安全性,避免攻击者猜测序列号进行会话劫持。

Q3:三次握手可以携带数据吗?

  • 前两次握手(SYN报文)不能携带数据,因为此时连接尚未建立,双方未准备好接收数据。
  • 第三次握手(ACK报文)可以携带数据。部分实现允许在第三次握手中捎带数据,以减少一次RTT(往返时间)。

Q4:SYN Flood攻击是什么?

攻击者伪造大量源IP,向服务器发送SYN,但不完成第三次握手,导致服务器维护大量半连接(占用内存),耗尽资源。防御手段包括:

  • SYN Cookie:服务器收到SYN后,不立即分配资源,而是根据连接信息计算一个Cookie作为初始序列号回复,若收到合法的ACK,再分配资源。
  • 增大半连接队列、缩短超时时间、使用防火墙过滤等。

Q5:同时打开(Simultaneous Open)如何处理?

双方同时向对方发送SYN,此时会进行四次交互(两个SYN和两个ACK),最终建立连接。这种情况较少见,但TCP规范支持。

8. 实际抓包示例

下面是用Wireshark捕获的一次HTTP访问过程中的TCP三次握手(客户端访问服务器80端口)。注意:Wireshark默认显示相对序列号(从0开始),实际原始序列号是随机值。

Pasted image 20260224222556

Pasted image 20260224223606
Pasted image 20260224223707
Pasted image 20260224223824

逐行解析

  1. 第1行(第一次握手):客户端(端口53354)向服务器(端口80)发送SYN报文。

    • Seq=0:相对序列号为0,表示这是本次连接的起始序列号(原始ISN为某个随机值)。

    • Win=65535:通知接收窗口大小为65535字节。

    • MSS=1460:通告本端支持的最大报文段长度为1460字节。

    • WS=256:窗口缩放因子为256,用于扩大窗口(实际窗口大小 = 窗口值 × 2^WS)。

    • SACK_PERM:支持选择性确认(SACK)选项。

  2. 第2行(第二次握手):服务器回复SYN-ACK报文。

    • Seq=1:服务器的相对序列号为1(原始序列号随机)。

    • Ack=1:确认号是1,表示期望收到客户端下一个序列号为1的字节(即确认了客户端的SYN)。

    • Win=64240MSS=1460SACK_PERMWS=128:服务器通告自己的参数。

  3. 第3行(第三次握手):客户端发送ACK报文。

    • Seq=1:客户端的下一个序列号(此时尚未发送数据)。

    • Ack=1:确认了服务器的SYN(期望收到服务器序列号为1的字节)。

    • Win=65280:更新窗口大小。

    • 此时连接建立,双方进入ESTABLISHED状态。

  4. 第4行:握手完成后,客户端立即发送HTTP GET请求(数据包长度为542字节),开始传输数据。

posted @ 2026-02-24 22:42  ffff5  阅读(1)  评论(0)    收藏  举报