news 2026/10/3 13:02:24

TCP 协议:报文头、连接管理、可靠传输与窗口

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TCP 协议:报文头、连接管理、可靠传输与窗口

TCP 协议:报文头、连接管理、可靠传输与窗口

课程:尚硅谷《嵌入式 Linux 应用层开发》第 6 章 Socket 编程
依据:2026-09-29 20:51 录音转写;课程 PDF 第 254—264 页。
本节边界:讲 TCP 原理和窗口机制;第 264 页末尾开始出现 Socket 常用函数,具体 API 留到下一节。

1. 本节知识路线

TCP 基本特征

TCP 首部字段

序列号与确认号

三次握手

四次挥手

累计确认与重传

接收窗口 rwnd

拥塞窗口 cwnd

实际发送限制 min_rwnd_cwnd

本节要回答四个核心问题:

  1. TCP 怎样区分连接和应用?
  2. TCP 怎样知道哪些字节已经收到、哪些需要重传?
  3. TCP 怎样防止压垮接收方?
  4. TCP 怎样避免向拥堵的网络继续高速发送?

2. TCP 的基本特征

TCP(Transmission Control Protocol)位于传输层,为应用提供面向连接、可靠、有序、双向的字节流服务。

特征正确含义
面向连接传输应用数据前先同步双方状态和初始序列号
可靠检测丢失和错误,并通过确认、重传等机制恢复
有序按字节序列号重排,按顺序交给应用
字节流应用看到连续字节,不保留每次send()的消息边界
全双工连接两端都有独立的发送序列空间,可以同时收发
端到端两端 TCP 实体维护连接状态,中间网络主要负责转发 IP 数据包

2.1 “可靠”不等于永远成功

网络中的 TCP 报文段仍然可能丢失、重复、乱序或损坏。TCP 的可靠性来自发现问题并尝试恢复。

如果网线断开、对端进程退出、系统崩溃或重试超过限制,连接仍然可能失败,应用会收到错误或超时。

2.2 一条 TCP 连接怎样区分

TCP 连接通常由四元组标识:

源 IP + 源端口 + 目的 IP + 目的端口

TCP 协议类型已经确定,因此通常不再写进这个四元组。服务端同一个监听端口可以接受多个客户端,因为每个连接的客户端 IP 或客户端端口不同。

3. TCP 首部总体结构

没有选项时,TCP 首部最小为 20 字节。存在选项时首部可以变长,Data Offset 字段的最大表示范围使 TCP 首部最大为 60 字节。

字段宽度主要作用
源端口、目的端口各 16 位标识两端应用 Socket
序列号seq32 位当前报文段中首个数据字节的编号
确认号ack32 位下一次期望收到的字节编号
Data Offset4 位TCP 首部长度,以 32 位字为单位
保留位与控制位若干位标志连接和传输状态
Window16 位通告接收窗口rwnd
Checksum16 位检测 TCP 首部和数据中的传输错误
Urgent Pointer16 位URG 有效时描述紧急数据位置
Options可变MSS、窗口缩放、SACK、时间戳等
Padding可变把首部补齐到 32 位边界
Data可变应用字节流的一部分

3.1 Data Offset 怎样换算

Data Offset 记录的是首部包含多少个 32 位字:

Data Offset = 5 → 5 × 4 字节 = 20 字节 Data Offset = 8 → 8 × 4 字节 = 32 字节 Data Offset = 15 → 15 × 4 字节 = 60 字节

填充只用于让 TCP 首部按 32 位边界结束,数据部分不要求补齐到 4 字节整数倍。

4. 需要重点认识的控制位

标志作用
SYN同步序列号,用于建立连接
ACK表示确认号字段有效
FIN发送方没有更多数据要发送,用于有序关闭一个方向
RST立即复位或拒绝连接
PSH提示接收端尽快把待交付数据推给应用
URG表示紧急指针字段有效
ECE、CWR用于显式拥塞通知 ECN

教材沿用只强调六个传统标志位的入门图。现代 TCP 基本规范还包括 ECE 和 CWR,保留位数量也与旧图不同。

RST 表示连接被复位或拒绝,并不等于 TCP 自动重新建立连接。是否重连由应用程序决定。

5. 序列号与确认号

5.1 序列号按字节编号

TCP 不给“第几个报文段”简单编号,而是给字节流中的字节编号。

假设当前第一个待发送字节的编号为 1000,每个报文段携带 100 字节:

报文段覆盖字节编号首部中的seq
11000—10991000
21100—11991100
31200—12991200

5.2 确认号表示“下一个想要的字节”

若接收方已经连续收到 1000—1299,就返回:

ack = 1300

这表示 1300 之前的连续字节已经收到,下一步期待 1300。

基本关系:

ack = 已连续收到的最后一个字节序号 + 1

5.3 SYN 和 FIN 也占用序列号空间

SYN 和 FIN 即使不携带普通应用数据,也各消耗一个序列号。因此握手和挥手时经常出现:

ack = 对方 seq + 1

6. TCP 状态先建立最小框架

教材列出 11 种状态:

状态含义
CLOSED没有连接
LISTEN服务端等待连接请求
SYN_SENT主动方已经发送 SYN
SYN_RECEIVED收到 SYN 并回复 SYN+ACK
ESTABLISHED连接已经建立,可传输数据
FIN_WAIT_1主动关闭方已发送 FIN
FIN_WAIT_2主动关闭方的 FIN 已被确认,等待对方 FIN
CLOSE_WAIT收到对方 FIN,等待本地应用关闭
CLOSING双方几乎同时主动关闭
LAST_ACK被动关闭方已发送 FIN,等待最后 ACK
TIME_WAIT主动关闭方等待旧报文消失并处理 FIN 重传

当前阶段先能认出LISTEN、ESTABLISHED、CLOSE_WAIT和TIME_WAIT。以后可用ss -tan对照实际连接状态。

7. 三次握手

假设客户端初始序列号为x,服务端初始序列号为y。

服务端客户端服务端客户端LISTENSYN_SENTSYN_RECEIVEDESTABLISHEDSYN=1, seq=xSYN=1, ACK=1, seq=y, ack=x+1ACK=1, seq=x+1, ack=y+1
次数发送方向关键字段作用
第一次客户端 → 服务端SYN, seq=x请求连接并给出客户端初始序列号
第二次服务端 → 客户端SYN+ACK, seq=y, ack=x+1确认客户端并给出服务端初始序列号
第三次客户端 → 服务端ACK, seq=x+1, ack=y+1确认服务端的 SYN

三次握手的核心作用是:

  • 确认两个方向都能通信;
  • 同步双方各自的初始序列号;
  • 建立连接状态,减少旧报文造成错误连接的风险;
  • 协商 MSS、窗口缩放、SACK 等 TCP 选项。

初始序列号不是教材图里固定的 0,实际实现会选择新的初始值。

8. 四次挥手

TCP 是全双工连接,两个发送方向要分别关闭。假设客户端先主动关闭:

被动关闭方主动关闭方被动关闭方主动关闭方FIN_WAIT_1FIN_WAIT_2CLOSE_WAIT,可继续发送剩余数据LAST_ACKTIME_WAITCLOSEDFIN=1, ACK=1, seq=uACK=1, ack=u+1FIN=1, ACK=1, seq=wACK=1, ack=w+1

第二次挥手后,主动关闭方已经不能再发送应用数据,但仍可以接收被动关闭方剩余的数据。这体现了 TCP 的半关闭能力。

8.1 为什么通常说四次

收到 FIN 后,内核可以马上确认;本地应用何时完成剩余发送并关闭,是另一个时间点,所以 ACK 和本端 FIN 通常分开发送。

实际通信中,如果时机合适,ACK 与 FIN 也可能合并到同一个报文段,抓包未必永远正好看到四个独立报文段。

8.2 TIME_WAIT 为什么存在

主动关闭方发送最后一个 ACK 后等待一段时间,主要用于:

  • 对方没收到最后 ACK、重传 FIN 时,仍能再次回复 ACK;
  • 让该连接的旧重复报文在网络中自然消失,避免干扰以后复用相同四元组的连接。

传统分析把等待时间写作2 × MSL。具体持续时间由操作系统实现决定,不要把它理解成所有系统都相同的固定秒数。

9. 可靠传输的几个基础机制

9.1 累计确认

ACK 确认的是某个序号之前连续收到的全部字节。

收到 0—99、100—199、200—299 → 可以只发送 ACK=300 → 表示 0—299 都已连续收到

若 100—199 丢失,却先收到 200—299,累计确认通常仍指向 100,表示缺口尚未补上。

9.2 延迟确认

接收方可以短暂等待,将多个确认合并,或把 ACK 搭载到反向数据上,以减少纯 ACK 报文数量。

延迟确认不是无限等待。具体策略和定时由 TCP 实现决定。

9.3 超时重传

发送方为未确认数据维护重传计时。当重传超时 RTO 到期仍未得到确认时,重传最早的未确认数据。

RTO 不是随意固定的常量,它会根据往返时间 RTT 的测量动态计算。

9.4 快速重传

接收方发现序列号缺口时,会继续确认期望的下一个字节。发送方连续收到 3 个重复 ACK 后,可以推断某段可能丢失,不等待 RTO 就先重传。

发送:100、200、300、400 其中 200 丢失 接收方收到 300、400 后仍重复回复 ACK=200 发送方收到足够的重复 ACK → 快速重传 seq=200

现代 TCP 还可能使用 SACK 精确说明已经收到的非连续区间。

10. 接收窗口rwnd:保护接收方

接收方读取应用数据的速度可能低于网络到达速度。TCP 把尚未被应用读取的数据暂存在接收缓冲区,并通过首部 Window 字段通告可用空间。

接收缓冲区总容量 - 当前已占用空间 = 可通告接收窗口 rwnd

发送方必须限制未确认数据,避免超出接收方通告的能力。这是流量控制。

接收方计算空闲缓冲区

在 ACK 中通告 rwnd

发送方限制在途数据

应用读取接收缓冲区

10.1 零窗口

当rwnd = 0时,发送方停止继续发送普通新数据。之后会通过零窗口探测等机制确认窗口是否重新打开,避免窗口更新丢失后双方永久等待。

Window 字段本身只有 16 位。高带宽高时延网络可以在连接建立时协商窗口缩放选项,使有效接收窗口超过 65535 字节。

11. 拥塞窗口cwnd:保护网络

接收方有足够缓冲区,不代表中间网络能承受同样的数据量。发送方还维护拥塞窗口cwnd,根据 ACK、丢包、ECN 等反馈估计路径承载能力。

窗口谁维护或通告保护对象
rwnd接收方通告接收端缓冲区和处理能力
cwnd发送方计算中间网络容量

11.1 慢启动

当路径能力未知时,发送方从较小拥塞窗口开始探测。每收到确认新数据的 ACK,窗口增加;从每个 RTT 的整体效果看,窗口大约呈指数增长。

“慢启动”指相对一次性高速注入数据更谨慎。它的增长阶段实际上可能很快。

11.2 拥塞避免

当cwnd达到慢启动阈值ssthresh后,增长变得保守。经典模型中,cwnd大约每个 RTT 增加一个 MSS,表现为近似线性增长。

11.3 重传超时后的处理

RTO 超时通常被视为较强的拥塞信号。经典模型会:

  1. 降低ssthresh;
  2. 把cwnd降到很小的损失窗口;
  3. 重传丢失数据;
  4. 重新进行慢启动,再转入拥塞避免。

11.4 快速恢复

三个重复 ACK 说明后续报文仍在到达,网络并非完全停滞。快速重传后可在降低窗口的同时保留 ACK 时钟,避免像超时那样完全从头探测。

不同拥塞控制算法处理细节不同。Linux 常见算法不只教材展示的经典 Reno 模型,因此课堂曲线用于理解“探测、发现拥塞、减速、再增长”的思想。

12. 教材窗口曲线怎样理解

教材用简化数值演示:

慢启动:1 → 2 → 4 → 8 拥塞避免:8 → 9 → 10 → 11 → 12 发生超时:降低阈值,cwnd 回到很小值 重新增长

这是一张概念图,不应把它当成现代实现逐个 ACK 的固定计算公式。

更准确的经典描述是:

  • 慢启动期间,每个确认新数据的 ACK 最多增加约一个 SMSS,因此每个 RTT 大约翻倍;
  • 拥塞避免期间,每个 RTT 总增量大约为一个 SMSS;
  • 初始窗口不一定是 1 MSS,现代规范允许更大的初始窗口;
  • Linux 具体采用的拥塞控制算法可能是 CUBIC 等,而不是完全照搬 Reno 曲线。

13. 实际发送限制

发送方必须同时服从接收端和网络路径两个限制:

允许的在途数据上限 ≈ min(rwnd, cwnd)

真正还能发送多少,还要减去已经发送但尚未确认的数据:

当前可继续发送量 ≈ min(rwnd, cwnd) - bytes_in_flight

因此:

  • rwnd小:接收方来不及处理;
  • cwnd小:网络被判断为拥堵或尚未探测出足够容量;
  • 两者都大:发送方仍受应用是否有数据、发送缓冲区、MSS 和协议实现等条件限制。

14. 流量控制与拥塞控制不要混淆

对比项流量控制拥塞控制
关注对象接收方是否处理得过来中间网络是否承载得住
主要变量rwndcwnd、ssthresh
信息来源接收方通告窗口ACK、丢包、超时、ECN 等网络反馈
调节主体接收方通告,发送方遵守发送方算法计算

教材第 262 页把cwnd也描述为“流量控制的基础”容易混淆。通常把rwnd对应的机制称为流量控制,把cwnd对应的机制称为拥塞控制。

15. 可以立即做的观察练习

15.1 查看 TCP 状态

ss-tan

重点找:

  • LISTEN
  • ESTAB
  • TIME-WAIT
  • CLOSE-WAIT

15.2 抓取握手和挥手

有管理员权限时,可以在访问某个测试服务期间抓包:

sudotcpdump-iany-nn'tcp port 8080'

观察:

  1. SYN;
  2. SYN, ACK;
  3. ACK;
  4. 数据阶段的seq、ack和win;
  5. 关闭阶段的FIN与ACK。

不要要求抓包中的序列号必须从 0 开始。抓包工具可能为了便于阅读显示相对序列号。

16. 录音与教材表述校正

  1. 转写中的PCP、PCB、DCB、TCB等多数应为TCP。
  2. TCP 可靠不表示数据在网络中从不丢失,而是协议能检测并恢复部分丢失;连接仍可能最终失败。
  3. TCP 是字节流,没有固定应用消息长度,也不保留send()边界。应用层必须自行设计消息边界。
  4. TCP 序列号对应字节位置,不是简单的报文段编号。
  5. 确认号表示下一期望字节,不是把对方序列号原样返回。
  6. SYN 和 FIN 各占用一个序列号,所以握手和挥手中确认号通常加一。
  7. 现代 TCP 首部包含 ECE 和 CWR 等控制位;教材六标志位图是简化或旧式表示。
  8. Checksum 用于错误检测,不提供加密或防篡改安全保证。
  9. RST 表示复位或拒绝连接,不会自动重新建立连接。
  10. 四次挥手是典型逻辑过程,实际 ACK 与 FIN 可能合并。
  11. TIME_WAIT 通常出现在主动关闭方,但同时关闭等路径会有所不同。
  12. rwnd是接收方通告的流量控制窗口;cwnd是发送方维护的拥塞控制窗口。
  13. 慢启动不是“每收到一个 ACK 就把整个 cwnd 翻倍”,而是每个 RTT 的整体效果近似翻倍。
  14. 拥塞避免不是“每个 ACK 都让窗口增加一个完整报文段”,经典目标是每个 RTT 约增加一个 MSS。
  15. 现代初始拥塞窗口不固定为 1 MSS;教材明确采用 1 只是为了画图讨论。
  16. 真实 TCP 实现存在 Reno、NewReno、CUBIC 等不同算法,教材曲线只表示经典基础思想。

17. 本节最低掌握标准

学完后应能回答:

  1. TCP 的面向连接、可靠、有序字节流分别表示什么?
  2. TCP 最小首部为什么是 20 字节?
  3. seq与ack分别怎样计算?
  4. SYN 和 FIN 为什么会让确认号加一?
  5. 三次握手每一步交换什么信息?
  6. 四次挥手为什么通常不能简单合成两次?
  7. TIME_WAIT 有什么作用?
  8. 累计确认、超时重传和快速重传有什么关系?
  9. rwnd与cwnd分别保护谁?
  10. 为什么发送限制取min(rwnd, cwnd)?
  11. 慢启动与拥塞避免的增长速度有什么区别?
  12. 为什么 TCP 应用仍然需要自行处理消息边界?

最低实践要求:

  • 能画出三次握手和四次挥手;
  • 能根据seq和数据长度算出下一个 ACK;
  • 能解释零窗口时发送方为什么暂停;
  • 能从ss -tan中认出常见 TCP 状态;
  • 能看懂抓包中的SYN、ACK、FIN、seq、ack和win。

18. PDF 页码与录音时间索引

主题PDF 页码录音时间
TCP 定义与特征254—25500:02—02:19
TCP 首部与字段255—25702:20—08:17
TCP 状态257—25808:18—09:33
三次握手258—25909:34—13:17
四次挥手与 TIME_WAIT259—26013:18—17:07
累计确认、延迟确认、超时重传260—26117:08—20:49
接收窗口与流量控制261—26220:50—22:35
拥塞控制基础262—26322:36—27:59
发送窗口min(rwnd, cwnd)26428:00—28:25
Socket 开发函数264 页末起下一节内容

进一步核对资料:

  • IETF Internet Standard:RFC 9293,Transmission Control Protocol
  • IETF TCP 拥塞控制基础:RFC 5681
  • IETF TCP 重传定时器:RFC 6298
  • IETF 窗口缩放与时间戳扩展:RFC 7323
  • IETF 较大初始窗口规范:RFC 6928

19. 下一步学习

下一节将把 TCP 原理映射到 Linux Socket API:

服务端:socket → bind → listen → accept → recv/send → close 客户端:socket → connect → send/recv → close

继续前至少要能解释:

  • 为什么服务端先进入LISTEN;
  • connect()对应三次握手的触发;
  • 为什么 TCP 的一次recv()不保证得到一条完整业务消息;
  • close()为什么不等于网络上立即完全消失。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 13:02:24

【技术专题】Mysql8 数据库 - Mysql8 客户端sqlyog安装以及配置

大家好,我是Java1234_小锋老师,最近更新 《一天学会 Mysql8 视频教程(无废话版) 》专辑,感谢大家支持。 本课程主要介绍和讲解 Mysql8简介,安装以及配置,客户端sqlyog 安装以及配置,数据库基本操作&#x…

作者头像 李华
网站建设 2026/10/3 13:01:16

AI Agent项目实战:工具调用、记忆、规划和可观测性

摘要:一篇能直接复用的项目实战 这是一篇可以直接照着做的大模型与智能体长文项目实战。项目面向“自动处理工单、查询数据库、生成报告和协调多步骤任务”,核心方法是“ReAct、计划执行、工具路由、短期/长期记忆、失败重试”,技术栈以Python、LangGraph、FastAPI、Postgr…

作者头像 李华
网站建设 2026/10/3 12:59:57

DRV8818驱动PIC18LF46K22:双极步进电机完整控制链实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华