详解TCP三次握手

前言

学习TCP三次握手之前,先了解一些核心前提:

1.TCP核心特性

TCP是面向连接、全双工、可靠传输的传输层协议。

  • 面向连接:通信前必须先建立专属连接,通信结束正常断开;
  • 全双工:客户端和服务端同时具备收发数据能力,双方各自拥有独立的发送缓冲区、接收缓冲区;
  • 连接本质:TCP 连接并不是物理链路,而是操作系统内核在两端维护的一套虚拟状态 + 核心参数(序列号、确认号、滑动窗口、MSS、校验和等)。
2. 三次握手的三大核心目的
  1. 验证客户端 发送 / 接收 能力正常;
  2. 验证服务端 发送 / 接收 能力正常;
  3. 同步双方初始序列号 ISN,为后续:数据去重、乱序重组、丢失重传、按序交付上层应用提供基础。
3.关键报文标志位/字段
标志位/字段 作用 规则
SYN 同步位,用于建立连接、同步序列号 只要携带 SYN=1 的报文,会消耗 1 个序列号
ACK 确认位,标识确认号是否有效 只有 ACK=1 时,头部的确认号才生效
seq 本次发送报文的起始序列号 全局单调递增,用来标记数据顺序
ack 期望收到对方下一个报文的序列号 ack = 对方上一次seq + 占用的字节数
ISN 初始序列号 客户端、服务端各自随机生成,禁止固定
4.两端初始状态

客户端(主动发起连接):初始状态 CLOSED;

服务端(被动等待连接):提前监听端口,初始状态 LISTEN。

三次握手完整全局总览

第一次握手:客户端 → 服务端:我要建连接,我的初始序号是 x;

第二次握手:服务端 → 客户端:收到你的序号,我同意建连接,我的初始序号是 y;

第三次握手:客户端 → 服务端:收到你的序号,我也确认同意,连接正式建立。

分步讲解

第一次握手:客户端 → 服务端(SYN 报文)

客户端应用调用 connect() 系统调用,主动向服务端监听端口发起连接请求。

TCP报文的核心内容:

标志位:SYN = 1,ACK = 0;

序列号:seq = x (客户端 ISN,随机生成);

无应用层数据、无载荷;

携带 TCP 可选参数:MSS(最大分段大小)、窗口缩放、SACK 等。

客户端从CLOSED变为SYN_SENT(已发送连接请求,等待服务端确认),服务端保持LISTEN 不变。

服务端收到该 SYN 报文后,不会立刻建立完整连接,会将该连接存入半连接队列(SYN 队列),等待二次确认。

第二次握手:服务端 → 客户端(SYN+ACK 报文)

服务端内核从网卡收到客户端的 SYN 报文,校验合法后,回复同步+确认复合报文。

TCP报文的核心内容:

标志位:SYN = 1、ACK = 1(双标志位同时置 1);

服务端序列号:seq = y(服务端 ISN,独立随机生成);

确认号:ack = x + 1(SYN 标志占用 1 个序列号,所以确认号要在对方 seq 基础上 +1);

无应用层数据。

服务端从LISTEN变为SYN_RCVD(已收到客户端连接请求,已回复确认),客户端保持 SYN_SENT 不变。

此时连接仍处于半连接状态,仅服务端单方面留存连接信息,未完全就绪。

第三次握手:客户端 → 服务端(ACK 报文)

客户端收到服务端的 SYN+ACK 报文,校验 ack=x+1 合法后,回复纯确认报文,完成最终协商。

TCP报文的核心内容:

标志位:ACK = 1,SYN = 0;

序列号:seq = x + 1(弥补第一次握手消耗的 1 个序号);

确认号:ack = y + 1(同理,服务端 SYN 占用 1 个序号);

第三次握手的 ACK 报文可以携带应用层数据。

客户端从SYN_SENT变为ESTABLISHED(连接已就绪,可收发数据);服务端收到该 ACK 后,SYN_RCVD变为ESTABLISHED;同时该连接从半连接队列移除,移入全连接队列(Accept 队列),等待服务端 accept() 系统调用取出连接。

至此,双方收发能力全部验证完成,双向 ISN 完全同步,全双工 TCP 连接正式打通。

问题

1.为什么必须三次握手?两次握手为什么不行?

两次握手会造成服务端资源浪费,产生无效半连接。

举个反例:

如果只有两次握手,

客户端发送延迟的失效 SYN 报文;

服务端收到后,直接回复 SYN+ACK,单方面进入 ESTABLISHED 状态,占用内核资源;

客户端早已断开,不会响应这个旧报文,服务端维持无效连接,内存 / 队列被占用。

所以服务端必须收到客户端的二次 ACK 确认,才会正式建立连接。

即使是过期的 SYN 报文,客户端收到陌生的服务端 ISN 后,会直接丢弃报文、不回复 ACK,服务端超时后自动释放半连接,避免资源浪费。

2.为什么第一次 / 第二次握手不能带数据,第三次可以?

第一次、第二次禁止携带数据

防止恶意攻击者利用大量 SYN 报文携带垃圾数据,疯狂消耗服务端内存、CPU;

连接未完成协商,双方缓冲区未就绪,无法处理业务数据。

第三次握手允许带数据

此时双向连接已完成校验、序列号同步完成,双方传输层状态就绪,可直接捎带业务数据,减少一次网络 IO,提升效率。

3.初始序列号 ISN 为什么要随机,不能固定?

防止TCP 序列号劫持攻击:攻击者无法预测下一次连接的 seq,不能伪造报文篡改数据;

防止历史残留报文干扰:网络中滞留的旧连接报文,不会和新连接的序列号冲突,避免数据错乱、重复接收。

4.SYN、FIN 为什么会消耗一个序列号?

SYN(建连)、FIN(断连)属于控制操作,和业务数据一样需要被确认。

占用 1 个序号可以统一 TCP 确认机制:控制报文 + 数据报文 共用一套序号规则,简化内核协议栈设计。

补充

  1. 两个核心队列(服务端)

    半连接队列(SYN Queue):

    存放 SYN_RCVD 状态的连接,也就是只收到客户端 SYN、还没收到第三次 ACK 的连接;

    全连接队列(Accept Queue):

    存放 ESTABLISHED 状态的连接,等待服务端应用通过 accept() 函数获取并使用。

  2. 异常场景

    服务端未收到第三次握手的 ACK:半连接队列中的连接会超时重传 SYN+ACK,多次重试失败后自动删除;

    半连接队列溢出:会导致新连接无法建立,引发SYN 洪水攻击风险。

总结

TCP 三次握手的本质:
通过2 次 SYN 同步双向序列号 + 1 次最终确认,在不可靠的网络中,用最小的交互次数,验证双方全双工收发能力、同步初始序列号、过滤无效连接请求,最终建立安全、可靠、有序的传输层连接。

相关推荐
不愿透露姓名的大鹏2 小时前
NetSpot结合iperf3精准测试局域网速率
网络
聊点儿技术2 小时前
网约车高风险环节的IP欺诈风险查询应用思路
网络·tcp/ip·风险评估·ip地址查询·ip风险画像·网约车平台·ip画像api
爱学习的小囧2 小时前
VMware ESXi 双管理网口配置全教程:新增 vmk1 端口 + 主备冗余 / 负载均衡双模式实操
运维·服务器·网络·windows·负载均衡·虚拟化
大卡片2 小时前
TCP与UDP通信
网络·网络协议·tcp/ip
Ether IC Verifier2 小时前
RDMA常用缩写及应用详解
网络·网络协议·tcp/ip·计算机网络·dpu
傻啦嘿哟2 小时前
本地部署 vs 云服务器部署:IP环境对采集成功率的影响有多大
运维·服务器·tcp/ip
TechWayfarer2 小时前
IP归属地API接入实战指南:3天内安全上线的评估与落地方法
网络·tcp/ip·安全
Dontla2 小时前
OSI七层网络模型(OSI Model:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层)物链网传会表应、TCP/IP模型
网络·网络协议·tcp/ip
IpdataCloud2 小时前
不同业务如何选IP查询更新频率?离线与在线协同策略
前端·网络协议·tcp/ip·html