【Linux】传输层协议TCP

本文主题内容

  • 掌握 TCP 报头格式
  • 理解序号、确认应答与超时重传
  • 理解三次握手与四次挥手
  • 掌握 TCP 状态转换
  • 理解滑动窗口与流量控制
  • 理解快速重传与拥塞控制
  • 理解延迟应答、捎带应答和字节流
  • 分析 TIME_WAITCLOSE_WAIT

引言:TCP 的复杂性来自传输控制。它不仅要把数据送到对端,还要处理丢包、重复、乱序、接收能力和网络拥塞。理解这些机制,需要把报头字段、状态机和缓冲区联系起来。

一、TCP 基本特点

TCP 全称 Transmission Control Protocol,主要特点:

  • 面向连接
  • 可靠传输
  • 有序字节流
  • 全双工
  • 提供流量控制
  • 提供拥塞控制

TCP 的可靠不是绝对保证应用成功处理,而是保证在连接有效时,把确认过的字节按顺序交付给接收应用;无法继续传输时会通过错误或连接关闭通知应用。

二、TCP 报头

TCP 基本报头为 20 字节,带选项时最多 60 字节。

2.1 端口号

源端口和目的端口用于进程分用。TCP 连接由五元组标识:

text 复制代码
源IP、源端口、目的IP、目的端口、TCP

2.2 序号与确认号

  • 序号:本报文段数据第一个字节在字节流中的编号
  • 确认号:期望对方下一次发送的字节序号

确认号具有累计确认语义。例如 ACK 为 5001,表示 5001 之前的字节已经连续收到。

2.3 报头长度

4 位报头长度以 4 字节为单位。值为 5 表示 20 字节,最大值 15 表示 60 字节。

2.4 标志位

常见标志:

  • SYN:建立连接,同步初始序号
  • ACK:确认号有效
  • FIN:发送方不再发送数据
  • RST:复位连接
  • PSH:提示接收端尽快向应用交付
  • URG:紧急指针有效

2.5 窗口大小

接收端通过窗口字段告诉发送端自己当前还能接收多少数据,用于流量控制。窗口扩大选项可以突破 16 位字段的直接范围。

三、可靠传输

3.1 确认应答

发送端把已发送但未确认的数据保存在发送缓冲区,收到 ACK 后才能释放相应范围。

3.2 序号解决的问题

序号和确认号可以:

  • 判断数据是否重复
  • 恢复正确顺序
  • 表示已经连续收到的范围
  • 支撑滑动窗口

接收端发现重复数据时会丢弃重复部分,但仍可能再次发送 ACK,帮助发送端恢复状态。

3.3 超时重传

发送数据后,如果在重传超时时间 RTO 内没有收到有效确认,发送端会重传。

RTO 不能固定得过小或过大:

  • 太小:正常延迟也会触发无意义重传
  • 太大:真正丢包后的恢复太慢

TCP 根据测量到的往返时间 RTT 及其波动动态估计 RTO,并在连续超时时执行退避。

TCP 可靠性的基础是序号、确认、超时重传和校验,它们共同处理丢失、重复、乱序与损坏。

四、三次握手

4.1 握手过程

  1. 客户端发送 SYN,携带初始序号 x
  2. 服务器发送 SYN + ACK,序号为 y,确认号为 x + 1
  3. 客户端发送 ACK,确认号为 y + 1

握手完成后双方进入 ESTABLISHED

4.2 为什么是三次

三次握手使双方确认:

  • 自己的发送能力正常
  • 自己的接收能力正常
  • 对方的发送与接收能力正常
  • 双方的初始序号已经同步

两次不足以让服务器确认客户端已经收到自己的初始序号,也更难避免旧连接请求造成状态混乱。

4.3 SYN Flood

服务器收到 SYN 后会保存半连接状态。攻击者大量发送请求但不完成握手,会消耗队列资源。

常见缓解方式包括 SYN Cookies、队列调整、速率限制和上游防护。

五、四次挥手

5.1 关闭过程

TCP 是全双工协议,两个发送方向需要分别关闭:

  1. 主动关闭方发送 FIN
  2. 被动关闭方发送 ACK
  3. 被动关闭方处理完剩余数据后发送 FIN
  4. 主动关闭方发送 ACK

中间两个报文在条件允许时可能合并,所以抓包中不一定总能看到严格分离的四个报文。

5.2 半关闭

一方发送 FIN 只表示自己不再发送,不妨碍继续接收对方数据。应用可以使用 shutdown(fd, SHUT_WR) 主动关闭写方向。

六、TCP 状态转换

6.1 服务端常见状态

text 复制代码
CLOSED -> LISTEN -> SYN_RCVD -> ESTABLISHED
ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED

6.2 客户端常见状态

text 复制代码
CLOSED -> SYN_SENT -> ESTABLISHED
ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2
-> TIME_WAIT -> CLOSED

6.3 TIME_WAIT

主动关闭方在发送最后 ACK 后进入 TIME_WAIT,通常等待 2MSL。

原因包括:

  • 最后 ACK 丢失时,可以重新发送
  • 让旧连接中的迟到报文在网络中消失,避免影响相同五元组的新连接

服务器大量 TIME_WAIT 不一定是 Bug,它说明服务器主动关闭了许多连接。应先确认协议设计和连接复用方式,再考虑参数调整。

6.4 CLOSE_WAIT

收到对端 FIN 后,本地进入 CLOSE_WAIT。如果长期大量存在,通常表示应用已经知道对端关闭,却没有及时调用 close

注意:CLOSE_WAIT 通常是应用资源释放问题,不能靠缩短 TCP 内核超时从根本上解决。

七、滑动窗口与流量控制

7.1 滑动窗口

如果每发送一段数据都等待 ACK,吞吐量会受到 RTT 严重限制。滑动窗口允许发送端在未收到确认前连续发送一定范围的数据。

发送缓冲区可以理解为:

text 复制代码
已经确认 | 已发送未确认 | 允许发送 | 暂时不能发送

收到累计 ACK 后,窗口向右滑动,已经确认的数据可以释放,新的数据进入可发送范围。

7.2 流量控制

接收端通过通告窗口 rwnd 告诉发送端剩余接收空间。发送端不能持续超过接收端处理能力。

当窗口为 0 时,发送端暂停普通数据,并周期性发送窗口探测,防止接收端窗口恢复通知丢失后双方永久等待。

八、快速重传

数据段丢失时,后续乱序数据会让接收端重复确认同一个期望序号。发送端连续收到多个重复 ACK 后,可以不等超时就重传缺失数据。

经典 TCP 通常在收到 3 个重复 ACK 后触发快速重传。现代 TCP 还可以使用 SACK 选择确认,更精确地描述已经收到的非连续区间。

九、拥塞控制

流量控制保护接收端,拥塞控制保护网络。实际发送窗口通常受二者共同限制:

text 复制代码
发送窗口 = min(rwnd, cwnd)

其中 cwnd 是拥塞窗口。

9.1 慢启动

连接开始时,发送端从较小拥塞窗口起步,每个 RTT 快速增加,用探测方式寻找可用容量。

9.2 拥塞避免

达到慢启动阈值后,窗口增长变得平缓,避免指数增长迅速压垮网络。

9.3 丢包后的处理

  • 超时通常被视为较严重拥塞,窗口明显降低
  • 重复 ACK 触发快速重传和快速恢复
  • 具体算法可能是 Reno、CUBIC、BBR 等

不能把某一张经典曲线当成所有操作系统当前实现的唯一行为,但慢启动、拥塞窗口和反馈调节的思想保持一致。

十、延迟应答与捎带应答

10.1 延迟应答

接收端不一定立即为每个小报文单独发送 ACK,可能短暂等待:

  • 看是否有数据可以一起返回
  • 看是否能确认更多连续字节
  • 给应用读取数据并扩大接收窗口的机会

延迟不能无限持续,否则会降低交互性能。

10.2 捎带应答

如果接收端也要发送业务数据,可以把 ACK 和响应数据放在同一个 TCP 报文段中,减少独立报文数量。

十一、面向字节流

TCP 为每个连接维护发送缓冲区和接收缓冲区。应用写入的是字节,不是独立消息:

  • 大块数据可能被拆成多个段
  • 多次小写可能被合并
  • 接收端每次读取的字节数由当前缓冲区和参数决定

因此所谓粘包并不是 TCP 报文粘在一起,而是应用层没有定义或正确解析消息边界。

十二、TCP 异常情况

12.1 进程终止

进程退出会关闭文件描述符,内核通常仍能发起正常 FIN 关闭。

12.2 主机崩溃或断网

无法发送 FIN 时,对端可能要等到重传超时、保活探测或业务心跳超时后才能发现。

12.3 RST

收到不存在连接的数据、访问未监听端口或连接状态严重不匹配时,可能收到 RST。应用读写会表现为连接重置错误。

12.4 Keepalive 与业务心跳

TCP Keepalive 由内核探测空闲连接,默认参数经常较长。业务心跳可以携带应用状态并使用更适合业务的超时,二者不能完全互相替代。

十三、总结

TCP 通过序号、确认、重传和校验实现可靠有序传输,通过三次握手建立双方状态,通过四次挥手分别关闭两个发送方向。滑动窗口提高吞吐量,接收窗口实现流量控制,拥塞窗口根据网络反馈调整发送强度。

TIME_WAIT 保护连接关闭和旧报文隔离,CLOSE_WAIT 长期堆积通常意味着应用没有关闭连接。TCP 提供字节流,不提供业务消息边界,应用层仍然必须设计协议并正确处理缓冲区。

理解 TCP 的关键,是把报头字段看成状态机和缓冲区的控制信息,而不是孤立地背诵三次握手与四次挥手。

相关推荐
Shell运维手记16 分钟前
Linux mdadm 软 RAID + LVM 完整综合笔记
linux·运维·笔记·5g
数据知道16 分钟前
恶意软件分析实验室搭建——沙箱、快照、网络隔离
网络·安全·web安全·网络安全
凤舞飘伶27 分钟前
服务器内存满日常运维命令
linux·运维·服务器
西柚小萌新28 分钟前
【论文阅读】--AgentPoison:通过投毒记忆库或知识库对LLM智能体进行红队测试
网络·安全
Fcy6481 小时前
Linux下 Socket编程 —— TCP网络编程
linux·网络·tcp/ip
IPdodo_1 小时前
静态 IP 访问异常排查:403/429 归因与迁移验收
服务器·网络·数据库·python·网络协议·php·性能测试
ouynagda1 小时前
HTTP协议与Socket网络编程笔记
网络·笔记·http
haerapi2 小时前
流式对话接口怎么选:SSE 与 WebSocket 的原理、实现和工程边界
网络·websocket·网络协议
砚凝霜2 小时前
【软考信息安全】第二章 网络攻击基础与常见技术方法
网络·安全·php