TCP建立连接:三次握手(每次握手发的字段及字段值的解释)

一、先明确 TCP 头部的关键字段(和三次握手强相关)
| 字段名 | 作用(三次握手中的意义) | 补充说明 |
|---|---|---|
| SYN | 标记 “同步序列编号”,用于发起连接协商 | 1 表示请求建立连接,0 表示正常数据 |
| ACK | 标记 “确认号有效”,用于确认收到对方的数据 | 1 表示确认,0 表示不确认 |
| seq | 发送方的 “初始序列号”(ISN,Initial Sequence Number) | 随机生成(防止旧连接干扰) |
| ack | 接收方的 “确认序列号”,期望对方下一个序列号 | 一般为 “收到的 seq + 1” |
二、三次握手每一步的字段解析(结合流程)
1. 第一步:客户 A→服务器 B,发 SYN 报文
- 字段内容:
SYN=1,ACK=0(默认,因为还没收到数据,不需要确认),seq=x,ack=任意(无意义,因为没收到数据) - 为啥发这些?
SYN=1:告诉 B “我(A)要发起连接,请求同步序列号”(相当于说 “我要和你建立连接,咱们商量一下数据怎么编号”)。seq=x:A 生成的 初始序列号(ISN),是一个随机数(比如系统随机选的 32 位整数,防止旧连接的残留报文干扰新连接)。ACK=0:因为 A 还没收到 B 的任何数据,所以不需要确认,ACK 置 0(只有收到数据后,ACK 才会置 1 并带确认号)。
2. 第二步:服务器 B→客户 A,发 SYN+ACK 报文
- 字段内容:
SYN=1,ACK=1,ack=x+1,seq=y - 为啥发这些?
SYN=1:B 回应 A 的连接请求,告诉 A “我(B)也同意同步序列号,建立连接”。ACK=1:告诉 A “我(B)确认收到你的 SYN 报文了”(通过ack=x+1体现)。ack=x+1:B 期望 A 下一个发送的序列号是x+1(因为 B 收到了 A 的seq=x,所以确认号是x+1,表示 “我收到了 seq=x 的报文,你下次发 seq=x+1 吧”)。seq=y:B 自己生成的 初始序列号(ISN),也是随机数(和 A 的x无关,各自独立选)。
3. 第三步:客户 A→服务器 B,发 ACK 报文
- 字段内容:
ACK=1,ack=y+1,seq=x+1(如果有应用层数据,还会带数据,但字段核心是这些) - 为啥发这些?
ACK=1:告诉 B “我(A)确认收到你的 SYN+ACK 报文了”。ack=y+1:A 期望 B 下一个发送的序列号是y+1(因为 A 收到了 B 的seq=y,所以确认号是y+1)。seq=x+1:A 的下一个序列号,延续第一步的seq=x(因为 TCP 是 面向字节流 的,每个字节都要有序号,即使没有数据,序列号也要推进。第一步的 SYN 报文占了seq=x,所以这里用seq=x+1,表示 “我接下来要发的数据从 x+1 开始”)。
三、字段值的 “为什么是这些”(核心逻辑)
初始序列号(seq)的随机性:
- 假设 seq 是固定值(比如每次都从 0 开始),如果网络中残留着旧连接的 SYN 报文(比如延迟的旧请求),新连接可能会被旧报文干扰(比如旧 SYN 的 seq=0 被误认为是新连接的请求)。
- 用随机的 ISN,能极大降低 “旧连接残留报文干扰新连接” 的概率,保证连接的唯一性。
确认号(ack)的规则:ack = 收到的 seq + 1
- TCP 是 可靠传输,需要确认 “对方发送的报文已收到”。
ack = 收到的 seq + 1表示 “我已经收到了 seq 及之前的所有字节,你下次从 seq+1 开始发”,确保数据不丢失、不重复。
SYN 与 ACK 标记的作用:
SYN是 “我要协商序列号,建立连接”,ACK是 “我确认收到你的报文”。- 第二步必须同时带
SYN(回应 A 的连接请求,协商自己的序列号)和ACK(确认收到 A 的 SYN 报文),所以是SYN+ACK。
四、总结:三次握手的字段设计,本质是 “可靠协商”
- seq 和 ack:解决 “数据怎么编号、怎么确认收到” 的问题,保证连接建立过程中,双方的 “序号协商” 和 “收到确认” 是可靠的。
- SYN 标记:明确 “我要发起 / 回应连接协商”,让双方知道 “现在是建立连接阶段”。
- ACK 标记:明确 “我确认收到你的协商请求”,避免一方 “喊话” 后,另一方没回应导致的 “单向连接”。
简单说,三次握手的字段就是 TCP 用来 “精准协商” 的 “语言”:
- 用
SYN说 “我要连接,这是我的序号”; - 用
ACK说 “我收到了,这是你的确认号,这是我的序号”; - 三次交互,让双方都确认 “我能发、你能收;你能发、我能收”,最终达成 “双向可靠连接”~
