详解 TCP
详解 TCP。
1. TCP 逐步完善
两个设备之间如何通网络传递数据已经知道了,但是如何知道数据包发给哪个程序呢?
这就是端口号的作用了。这就将主机到主机之间的通信升级为进程到进程之间的通信。
如果主机 A 发送给主机 B 的数据丢失了,此时如何让主机 A 知道呢?
主机 A 每发送的一个包都要收到主机 B 的确认,也就是 ACK。如果在规定时间内没有收到 ACK,就重传。这就是停止等待协议。
但是效率较低,只有在 ACK 收到后才能发送第二个包。
于是又改为了流水线发送数据包,流水线接收 ACK 的方式。
但是可能发送数据包的顺序和接收数据包的顺序不同。
于是在发送数据包中加一个序号,也就是 seq。同时在主机 B 的响应的 ACK 中也加一个确认号。
另外,如果主机 A 收到了 ACK3,这不仅代表主机 B 接收到了数据包 3,也代表主机 B 接收到了数据包 1 和 数据包 2。 这就是累计应答或累计确认。
如果主机 B 的接收能力跟不上主机 A 的发送能力。
这就需要主机 A 根据主机 B 的接收能力调整发送速度。
那么主机 B 如何将自己的接收能力告诉给主机 A 呢?
这就需要主机 A 给主机 B 发送数据包时要加上自己接收能力的窗口大小。同时主机 B 给主机 A 回应时也要加上自己接收能力的窗口大小。然后主机 A 需要根据这两类窗口大小做流量控制。这就是 可变窗口。
如果受到网络质量的影响,造成了网络拥塞。
同样需要设置一个窗口大小。这个窗口的大小需要主机 A 不断地试探。具体就是慢开始、拥塞避免、快重传和快恢复。
最终的通信窗口就是可变窗口与拥塞窗口的最小值。
2. TCP 报文段的首部格式
2.1 端口号 Source Port
用来标识同一台计算机的不同的应用进程。
- 源端口 Source Port:2 字节。源端口和IP地址的作用是标识报文的返回地址。
- 目的端口 Destination Port:2 字节。端口指明接收方计算机上的应用程序接口。
TCP 报头中的源端口号和目的端口号同 IP 数据报中的源 IP 与目的 IP 唯一确定一条 TCP 连接。
2.2 序号 Sequence Number
4 字节。首部中的序号字段值是指本报文段所发送的数据的第一个字节的序号。
2.3 确认号 Acknowledgement Number (meaningful when ACK bit set)
4 字节。是期望收到对方的下一个报文段的第一个数据字节的序号。
若确认号 = N,代表到序号 N-1 为止的所有数据都已正确收到。
2.4 数据偏移 Data Offset
4 位。它指出TCP报文段的数据起始处距离 TCP 报文段的起始处有多远。这个字段实际上是指TCP报文段的首部长度。
由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。
但应注意,“数据偏移”的单位是 32 位字(即以 4 字节长的字为计算单位)。由于 4 位二进制数能够表示的最大十进制数字是 15 ,因此数据偏移的最大值是 60 字节,这也是 TCP 首部的最大长度(即选项长度不能超过40字节)。
2.5 保留 Reserved
占 6 位。保留为今后使用。
2.6 控制位
2.6.1 紧急 URG Urgent Pointer
紧急指针标志,为 1 时表示紧急指针有效,为 0 则忽略紧急指针。
2.6.2 确认 ACK Acknowledgment
确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。
2.6.3 推送 PSH Push
push标志,为 1 表示是带有 push 标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。
2.6.4 复位 RST Reset
重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求。
2.6.5 同步 SYN Synchronization
同步序号,用于建立连接过程,在连接请求中,SYN=1 和 ACK=0 表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1。
2.6.6 终止 FIN Finish
finish 标志,用于释放连接,为1时表示发送方已经没有数据发送了,即关闭本方数据流。
2.7 窗口 Window
滑动窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小时一个16bit字段,因而窗口大小最大为65535。
2.8 校验和 Checksum
2 字节。此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。
2.9 紧急指针 Urgent Pointer
2 字节。只有当 URG 标志置 1 时紧急指针才有效。URG = 1 时,此报文段数据由紧急数据和普通数据组成。紧急指针的值指出了紧急数据的末尾在本报文段的位置。
当紧急数据处理完,TCP 就告诉应用程序回到正常操作。
当窗口为 0 时,也可以发送紧急数据。
2.10 选项 Options
长度可变,最大为 40 字节。
好的,下面是对 TCP 三次握手(Three-way Handshake) 的详细讲解,内容包括 概念、过程、目的、状态变化、报文格式分析 以及 常见误区和面试高频问题。
3. 三次握手
三次握手(Three-way Handshake)是 TCP 建立连接 的过程。
- 确保客户端和服务端都能发送、接收数据;
- 同步双方的序列号(Sequence Number)和确认号(Acknowledgment Number);
- 建立可靠的全双工通信通道。
3.1 三次握手过程详解
- 客户端(Client)、服务端(Server)
TCP 报文段包含关键标志位:
- SYN:同步序列号,用于发起连接
- ACK:确认应答
- seq:序列号(Sequence Number)
- ack:确认号(Acknowledgment Number)
3.1.1 第一步:客户端 → 服务端(SYN)
客户端发送一个 SYN 报文 来请求建立连接。
| 字段 | 值 |
|---|---|
| SYN = 1 | 表示请求建立连接 |
| seq = x | 客户端随机产生的初始序列号 |
此时客户端进入状态:SYN_SENT
目的:告诉服务器“我要建立连接”,发送自己的初始序列号
3.1.2 第二步:服务端 → 客户端(SYN + ACK)
服务端收到 SYN 后,如果同意连接,则回复一个 SYN+ACK 报文。
| 字段 | 值 |
|---|---|
| SYN = 1 | 同意建立连接 |
| ACK = 1 | 确认收到客户端的 SYN |
| seq = y | 服务端随机产生的初始序列号 |
| ack = x + 1 | 确认号为客户端的序列号 + 1 |
此时服务端进入状态:SYN_RECEIVED
目的:同意连接请求、发送自己的初始序列号、确认客户端的序列号
3.1.3 第三步:客户端 → 服务端(ACK)
客户端收到服务端的 SYN+ACK 报文后,发送一个 ACK 确认报文。
| 字段 | 值 |
|---|---|
| ACK = 1 | 确认应答 |
| seq = x + 1 | 客户端下一个要发送的数据序列号 |
| ack = y + 1 | 确认号为服务端的序列号 + 1 |
此时客户端进入状态:ESTABLISHED 服务端收到此报文后,也进入:ESTABLISHED 连接建立完成
3.2 每次握手的结果
| 握手次数 | 能确认的能力 | 存在问题 | | —- | ——————- | ————— | | 一次 | 只能确认客户端能发、服务端能收 | 服务端无法知道客户端是否能接收 | | 两次 | 能确认双方能发能收一部分信息 | 客户端无法确认服务端的接收能力 | | 三次 | 双方都确认发送+接收能力 | 安全可靠 |
3.3 常见问题
3.3.1 SYN 报文丢失了怎么办?
客户端超时后会重传 SYN 报文,通常重试 3~5 次后放弃连接。
3.3.2 三次握手中能携带数据吗?
- 前两次(SYN、SYN+ACK)不携带数据;
- 第三次(ACK)可以携带数据,但一般实际实现中不会,这样可以防止遭受 SYN 攻击。
3.3.3 什么是半连接队列?
- 服务端收到 SYN 后但未收到最后 ACK 前,会把该连接放入 半连接队列(SYN Queue);
- 如果 ACK 到达,连接会移到 全连接队列(Accept Queue);
- 攻击者可通过发送大量 SYN 不回应 ACK → SYN Flood 攻击。
4. 四次挥手
四次挥手(Four-way Handshake) 是指 TCP 连接的断开过程。 由于 TCP 是全双工(Full-duplex)通信,每个方向都必须单独关闭, 因此断开连接需要 四次报文交互。
4.1 核心思想
建立连接时,双方几乎同时做好“收发准备” → 三次握手即可。 关闭连接时,双方的关闭是独立的、单向的:
- 一方先说“我不发了”,但可能还要继续接收对方的数据;
- 所以,不能一口气“对称地关闭”,必须分两对关闭动作。
4.2 四次挥手过程详解
- 客户端(Client):主动发起关闭请求;
- 服务器(Server):被动关闭。
4.2.1 第一步:客户端 → 服务端(FIN)
客户端发送一个 FIN 报文段,表示:“我已经没有数据要发送了,但仍然可以接收你的数据。”
| 标志位 | 含义 |
|---|---|
| FIN = 1 | 结束发送数据 |
| seq = u | 客户端当前的序列号 |
客户端进入状态:FIN_WAIT_1
4.2.2 第二步:服务端 → 客户端(ACK)
服务端收到 FIN 后,发送一个 ACK 确认报文:
| 标志位 | 含义 |
|---|---|
| ACK = 1 | 确认收到客户端的 FIN |
| ack = u + 1 | 确认号为客户端序列号 + 1 |
服务端进入状态:CLOSE_WAIT 客户端进入状态:FIN_WAIT_2
此时,客户端处于半关闭状态(只接收不发送)。
4.2.3 第三步:服务端 → 客户端(FIN)
当服务器把剩余的数据都发送完后,也发送一个 FIN 报文,告诉客户端:“我也没有数据要发了。”
| 标志位 | 含义 |
|---|---|
| FIN = 1 | 结束发送数据 |
| seq = v | 服务端当前序列号 |
服务端进入状态:LAST_ACK
4.2.4 第四步:客户端 → 服务端(ACK)
客户端收到服务端的 FIN 报文后,回复 ACK 确认报文:
| 标志位 | 含义 |
|---|---|
| ACK = 1 | 确认收到服务端的 FIN |
| ack = v + 1 | 确认号为服务端序列号 + 1 |
客户端进入状态:TIME_WAIT 服务端收到后进入:CLOSED 客户端等待 2MSL 时间后也进入:CLOSED
连接彻底终止。
5. 常见问题
5.1 为什么要“四次”而不是“三次”?
TCP 是全双工通信,双方的关闭是独立的。
- 发送 FIN 表示 “我不发了”;
- 接收 ACK 只是确认“对方知道我不发了”;
- 但对方可能还有数据没发完,所以要等它自己再发一个 FIN。
因此:一次 FIN+ACK 只能关闭单向连接,双向都要关闭,就需要四次。
5.2 TIME_WAIT 状态的作用?
客户端在最后发送 ACK 后,会进入 TIME_WAIT 状态(持续 2MSL 时间)。
防止旧连接的报文干扰新连接
- 让网络中残留的旧 TCP 报文完全消失;
确保最后的 ACK 能被服务端接收到
- 如果服务端未收到最后的 ACK,会重发 FIN;
- 若客户端立即关闭,ACK 就无法再次发送,连接状态不确定。
MSL(Maximum Segment Lifetime):报文在网络中的最长生存时间。
5.3 为什么 TCP 连接关闭需要四次挥手?
因为 TCP 是全双工的,关闭连接需要双方各自单独关闭发送方向。 一方发送 FIN 表示自己不再发送,但可能仍要接收对方的数据。 所以对方必须等到数据发送完后再发 FIN,总共需要四次报文。
5.4 TIME_WAIT 为什么要等待 2MSL?
为防止旧连接报文干扰新连接,并确保最后一个 ACK 能够成功重传。 若服务端未收到 ACK,会重发 FIN,此时客户端仍在 TIME_WAIT,可以再次确认。
5.5 如果客户端立即关闭(不进入 TIME_WAIT)会怎样?
可能造成服务端仍处于 LAST_ACK 状态,重复发送 FIN,连接异常。 或旧连接的报文被误认为新连接的,导致数据混乱。
6. 缩写对照表
| 英文全称 | 英文缩写 | 中文全称 |
|---|---|---|
| Transmission Control Protocol | TCP | 传输控制协议 |
| Acknowledgment | ACK | 确认应答(确认信号) |
| Synchronization | SYN | 同步序列号(同步信号) |
| Finish | FIN | 结束(终止)标志 |
| Reset | RST | 重置标志 |
| Push | PSH | 推送标志 |
| Urgent | URG | 紧急标志 |
| Sequence Number | SEQ | 序列号 |
| Acknowledgment Number | ACK Number | 确认号 |
| Source Port | — | 源端口 |
| Destination Port | — | 目的端口 |
| Data Offset | — | 数据偏移 |
| Checksum | — | 校验和 |
| Urgent Pointer | — | 紧急指针 |
| Window | — | 窗口(滑动窗口大小) |
| Options | — | 选项字段 |
| Maximum Segment Lifetime | MSL | 报文最大生存时间 |
| Time Wait | TIME_WAIT | 等待计时状态 |
| Synchronization Sent | SYN_SENT | 同步已发送状态 |
| Synchronization Received | SYN_RECEIVED | 同步已接收状态 |
| Established | ESTABLISHED | 已建立连接状态 |
| Finish Wait 1 | FIN_WAIT_1 | 等待对方结束阶段 1 |
| Finish Wait 2 | FIN_WAIT_2 | 等待对方结束阶段 2 |
| Close Wait | CLOSE_WAIT | 等待关闭状态 |
| Last Acknowledgment | LAST_ACK | 最后确认状态 |
| Closed | CLOSED | 关闭状态 |
| Full Duplex | — | 全双工通信 |
| Three-way Handshake | — | 三次握手 |
| Four-way Handshake | — | 四次挥手 |
| Slow Start | — | 慢开始算法 |
| Congestion Avoidance | — | 拥塞避免 |
| Fast Retransmit | — | 快重传 |
| Fast Recovery | — | 快恢复 |
| Sliding Window | — | 滑动窗口机制 |
| Stop and Wait Protocol | — | 停止等待协议 |
| Congestion Window | — | 拥塞窗口 |
| Variable Window | — | 可变窗口 |
| Half-Open Connection | — | 半连接(半开连接) |
| SYN Flood Attack | — | SYN 洪泛攻击 |
| Accumulative Acknowledgment | — | 累计确认 |
| Maximum Segment Size | MSS | 最大报文段长度 |
| Flow Control | — | 流量控制 |
| Congestion Control | — | 拥塞控制 |
7. References
- 🔗你管这叫TCP?
- 🔗计算机网络-一次TCP通信过程分析
- 《计算机网络》 谢希仁 第八版
- 🔗Wikipedia-Transmission Control Protocol
- 《TCP/IP 网络编程》




