ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux网络:传输层TCP协议

Linux网络:传输层TCP协议 TCP 是计算机网络传输层的核心协议之一。相较于 UDP 协议TCP 最核心的特性为面向连接、可靠传输、面向字节流。想要真正吃透 TCP 协议不能只死记“三次握手”“四次挥手”等碎片化结论核心是先搞懂TCP 报文的完整结构、每个字段的具体作用。本文将从完整的 TCP 报文格式入手逐层拆解 TCP 的核心工作机制打通报文结构与可靠传输的底层逻辑。一、认识完整的 TCP 报文结构TCP 报文是 TCP 数据传输的基本单元完整格式如下这张报文结构图是理解 TCP 所有机制的核心蓝图。从组成上划分TCP 报文分为两大模块TCP报文 │ ├── TCP报头 │ ├── 源端口 │ ├── 目的端口 │ ├── 序号 │ ├── 确认序号 │ ├── 首部长度 │ ├── 标志位 │ ├── 窗口大小 │ ├── 校验和 │ ├── 紧急指针 │ └── 选项 │ └── 数据TCP 基础报头固定长度为20 字节若携带扩展选项报头长度会动态增加最大可达 60 字节。二、TCP 报头的底层逻辑在 Linux 内核中系统通过struct tcp_hdr结构体解析和封装 TCP 报头是内核管理 TCP 协议的核心数据结构。从网络数据封装流程来看TCP 报文的生成过程可简化为TCP协议 ↓ 准备TCP报头 ↓ 填写源端口、目的端口、序号、确认序号、 窗口、标志位等核心信息 ↓ 拼接上层业务数据 ↓ 生成完整TCP报文Linux 网络协议栈依托sk_buff结构体统一管理所有网络报文TCP 数据包的内存组织形式如下sk_buff │ ↓ ┌─────────────────┐ │ TCP报头 │ ├─────────────────┤ │ TCP数据 │ └─────────────────┘数据接收时协议栈会逐一解析 TCP 报头字段完成数据校验、排序、分发等操作。需要注意的是TCP 报头中所有多字节字段在网络传输中统一采用网络字节序大端序主机字节序与网络字节序的转换由系统协议栈自动完成。三、源端口与目的端口数据的精准投递标识TCP 报文头部最前端的两个字段为源端口号和目的端口号是数据精准交付的核心标识┌────────────────────┬────────────────────────────┐ │ 16位源端口号 │ 16位目的端口号 │ └────────────────────┴────────────────────────────┘两个字段各占用 16 位2 字节端口取值范围为 0~65535。以客户端与服务器通信为例客户端 服务器 192.168.1.10 192.168.1.20 端口 50000 端口 8080 50000 ─────────────→ 8080客户端发起请求时报文的源端口为自身临时端口 50000目的端口为服务器服务端口 8080。服务器接收报文后通过目的端口匹配对应的 TCP 连接与上层应用程序。完整的数据投递逻辑如下TCP报文 ↓ 解析目的IP定位目标主机 ↓ 解析目的端口匹配对应TCP连接 ↓ 绑定对应socket文件描述符 ↓ 交付给目标应用程序在 Linux 内核中接收完成的 TCP 报文会被挂载到对应 socket 的接收队列等待应用程序通过read()、recv()等系统调用读取数据。四、序号TCP 可靠传输的核心基石TCP 报文的第三个核心字段为 32 位序号是 TCP 实现可靠、有序传输的核心┌──────────────────────────────────────────────────┐ │ 32位序号 │ └──────────────────────────────────────────────────┘需要重点区分TCP 序号并非报文编号而是对字节流中每一个数据字节的全局编号。例如发送字符串ABCDE若首个字节的起始序号为 1000字节与序号的对应关系如下A B C D E ↓ ↓ ↓ ↓ ↓ 1000 1001 1002 1003 1004本次发送 5 个字节后下一次数据的起始序号将从 1005 开始递增。简言之TCP 序号的核心作用是标记当前数据在整条 TCP 字节流中的绝对位置。五、序号的核心作用一剔除重复数据TCP 序号首要解决的是数据重传导致的重复接收问题。网络传输中普遍存在 ACK 报文丢失的场景A发送数据 │ ├────────→ B │ │ │ ↓ │ B成功接收数据 │ │ B返回的ACK报文丢失 ↓ A未收到ACK判定数据丢失 │ ↓ A触发超时重传再次发送相同数据 │ └────────→ B此时 B 会收到两份完全相同的数据而序号是识别重复数据的唯一依据。两次传输的报文序号均为 1000B 可通过序号判断该段数据已接收直接丢弃重复报文避免数据重复交付给应用层。核心结论序号帮助 TCP 识别重传数据规避重复交付问题。六、序号的核心作用二重组乱序数据网络传输本身不保证数据包有序到达不同报文可能经由不同路由链路导致接收端收到乱序数据。例如 A 依次发送四段起始序号为 1000、2000、3000、4000 的数据网络传输时序错乱1000 ───────────────→ 2000 ───────→ 3000 ───────────────────→ 4000 ─────→B 最终的接收顺序为 1000、2000、4000、3000与发送顺序不一致。此时 TCP 会依托序号对乱序数据进行排序重组接收乱序数据 1000、2000、4000、3000 ↓ 根据序号重新排序 1000、2000、3000、4000 ↓ 有序交付至应用层核心结论TCP 的数据有序性并非网络天然提供而是通过序号在接收端主动重组实现。七、确认序号告知对方后续传输起始位置与序号配对的核心字段为 32 位确认序号是 TCP 应答机制的核心┌──────────────────────────────────────────────────┐ │ 32位确认序号 │ └──────────────────────────────────────────────────┘两个字段的分工清晰明确序号标识本次发送数据的起始位置确认序号标识当前已接收的字节终点告知对方下一次数据的起始发送位置简单示例A 向 B 发送起始序号 1000、长度 1 的数据B 接收成功后返回的确认序号为 1001。该应答的含义为1001 之前的所有字节已全部接收完毕后续数据请从 1001 序号开始发送。八、TCP 累积确认机制TCP 采用累积确认机制无需对每一段数据单独应答大幅提升传输效率。假设 A 依次发送起始序号 1000、2000、3000、4000 的四段数据正常应答流程如下A B 1000 ───────────────────→ ←────────────────── 1001 2000 ───────────────────→ ←────────────────── 2001 3000 ───────────────────→ ←────────────────── 3001 4000 ───────────────────→ ←────────────────── 4001若中间某条 ACK 报文丢失例如 3001 应答丢失最终 A 仅收到 1001、2001、4001 三条应答。根据累积确认规则4001 的应答可间接确认 4001 之前的所有字节均已接收即便 3001 应答丢失也无需重传对应数据有效避免了单一 ACK 丢失导致的无效重传。九、序号与确认序号分离的核心原因TCP 是全双工通信协议通信双方可同时双向传输数据A ─────────→ B A向B发送数据 A ←───────── B B向A发送数据基于全双工特性单个 TCP 报文可同时完成两项工作携带本方传输数据、应答对方已传输数据也就是捎带应答机制。因此 TCP 报头必须同时设置独立的序号和确认序号字段分别维护两个方向的传输状态互不干扰。十、TCP 无数据长度字段的底层原因对比 UDP 报文TCP 报头中没有专门的“数据长度”字段核心原因是 TCP 的协议特性——面向字节流。应用层多次调用写入接口发送数据时TCP 会将所有数据整合为一条连续的字节流不保留应用层的消息边界。例如write(fd, hello, 5); write(fd, world, 5);接收端读取数据时不会严格对应两次写入操作可能出现分段读取、合并读取等多种情况// 可能的读取结果1 read() → hell read() → oworl read() → d // 可能的读取结果2 read() → helloworldTCP 仅负责保证字节流的完整性和有序性不干预应用层消息的边界划分。消息拆分、解析的逻辑由上层应用协议自行实现因此 TCP 无需定义数据长度字段。十一、首部长度区分报头与数据的边界标识TCP 报头长度不固定20~60 字节接收端需要通过首部长度字段精准区分报头和业务数据的边界┌────────┐ │首部长度 │ └────────┘该字段占用 4 位二进制不直接存储字节数固定以4 字节为最小单位进行换算首部长度值 5实际报头长度 5×4 20 字节基础报头首部长度值 10实际报头长度 10×4 40 字节携带扩展选项4 位字段理论取值范围为 0~15TCP 有效取值为 5~15对应报头长度 20~60 字节。十二、TCP 报头与数据的分离逻辑基于首部长度字段TCP 可精准解析报文结构。以 40 字节报头为例┌─────────────────────────────┐ │ TCP基础报头 │ 20字节 ├─────────────────────────────┤ │ TCP选项 │ 20字节 ├─────────────────────────────┤ │ 数据 │ └─────────────────────────────┘首部长度换算后为 40 字节代表报文前 40 字节为完整 TCP 报头40 字节之后的所有内容均为业务数据。完整解析流程如下收到完整TCP报文 ↓ 读取前20字节基础报头 ↓ 解析首部长度字段 ↓ 换算得到完整报头字节数 ↓ 跳过报头区域 ↓ 剩余字节即为TCP业务数据十三、窗口大小TCP 流量控制的核心16 位窗口大小字段是 TCP 实现流量控制的关键用于避免发送方发送速率过快导致接收方缓冲区溢出┌──────────────────────────────┐ │ 16位窗口大小 │ └──────────────────────────────┘通信场景逻辑如下A B 持续发送数据 A ───────────────────────→ B ↓ 数据存入接收缓冲区 ┌─────────┐ │ 剩余空间 │ └─────────┘B 会实时检测自身接收缓冲区剩余空间将剩余可接收字节数写入窗口大小字段通过 ACK 报文告知 A。A 接收窗口大小信息后会动态调整发送速率确保发送数据量不超过 B 的接收能力。完整流量控制流程B检测接收缓冲区剩余空间 ↓ 计算当前可接收数据容量 ↓ 更新窗口大小字段 ↓ 通过ACK报文同步给发送方A ↓ A根据窗口大小动态调整发送量核心作用窗口大小解决了收发双方速率不匹配问题防止接收方缓冲区被撑爆。十四、零窗口探测机制流量控制补充结合窗口大小与流量控制机制TCP 定义了零窗口探测机制用于规避流量控制死锁问题。当接收方应用层读取缓慢、缓冲区占满时会通过窗口大小字段告知发送方「窗口为 0暂停发送数据」。此时发送方停止传输业务数据但不会彻底断开链路会周期性发送仅含报头、不带业务数据的探测报文轮询检测接收方窗口状态。该机制的核心价值持续监听接收方缓冲区恢复状态一旦窗口恢复可用发送方可立即恢复数据传输避免因双方状态同步失效导致的流量控制死锁保障连接长期稳定可用。十五、TCP 可靠性与传输效率的平衡逻辑若 TCP 采用“单发单等”模式发送一段数据、等待 ACK、收到应答后再发送下一段传输效率会极低。为兼顾可靠与高效TCP 支持批量发送、异步应答机制可连续发送多段数据无需逐段等待 ACKA B 数据1 ───────────────────────→ 数据2 ───────────────────────→ 数据3 ───────────────────────→ 数据4 ───────────────────────→ 统一等待对应ACK应答发送操作与 ACK 等待操作并行重叠大幅提升传输效率。后续结合发送窗口、拥塞控制机制TCP 可动态适配网络状态实现高效、稳定的可靠传输。十六、标志位定义 TCP 报文的功能属性TCP 报文格式固定但不同报文的功能差异极大建连、传数、应答、断连、异常复位、紧急推送等标志位是区分报文功能的核心标识┌────────┬──────────┬──────────────────────────────┐ │首部长度 │ 保留位 │ 标志位 │ 窗口大小 │ └────────┴──────────┴──────────────────────────────┘TCP 核心标志位共 6 个标准优先级顺序为SYN、ACK、FIN、RST、PSH、URG。现代 TCP 还扩展了 ECE、CWR 拥塞控制标识。下文按标准顺序逐一拆解核心标志位原理与落地场景。十七、SYN 标志位连接建立请求标识SYN 标志位专门用于TCP 三次握手建连。客户端调用connect()发起建连请求时会构造SYN1的请求报文。简化版三次握手流程客户端 服务器 SYN1建连请求 ───────────────────────────────→ SYN1ACK1同意建连应答 ←─────────────────────────────── ACK1确认收到回复 ───────────────────────────────→关键认知网络中传输的并非单独的标志位而是完整 TCP 报文第二次握手报文同时携带 SYN、ACK 两个有效标志位兼具请求与应答功能。17.1 三次握手的核心通信逻辑抛开内核状态机仅从通信本质理解三次握手第一次握手SYN客户端告知服务器请求建立 TCP 连接第二次握手SYNACK服务器确认收到请求同时告知客户端自身可正常通信第三次握手ACK客户端确认收到服务器回复告知服务器自身可正常通信三次交互后双方均确认双向收发能力正常TCP 连接正式建立。十八、ACK 标志位数据应答标识ACK 全称 Acknowledge代表数据确认应答是 TCP 可靠传输的核心保障。所有正常传输的 TCP 报文绝大多数都会将 ACK 置为 1。通信示例A B 业务数据 ────────────────────────→ ←────────────────────── ACK应答报文B 回复的应答报文中ACK1同时携带最新的确认序号和窗口大小同步告知 A 数据接收进度与当前接收能力。三者协同逻辑ACK 标识报文为应答报文确认序号同步接收位置窗口大小同步接收能力。十九、FIN 标志位连接关闭请求标识TCP 全双工特性决定了连接关闭需要双向分别断开FIN 标志位用于发起单向关闭请求。关闭流程分为两个阶段A 无数据发送发起关闭请求A B FIN1 ─────────────────────────→ ←────────────────────── ACK1此时A→B 方向传输关闭B→A 方向仍可正常通信。B 数据发送完毕后发起反向关闭请求A B ←────────────────────── FIN1 ACK1 ─────────────────────────→双向均断开后TCP 连接彻底销毁该过程即为四次挥手。19.1 建连三次、断连四次的核心差异建立连接仅需三次交互核心原因是请求与应答可合并服务器收到 SYN 建连请求后可直接在同一个报文中携带 SYN自身建连请求和 ACK应答客户端两步操作合并为一次报文传输。关闭连接必须四次交互核心原因是关闭请求与应答无法强制合并当 B 收到 A 的 FIN 关闭请求时仅能优先返回 ACK 应答确认关闭请求但 B 可能仍有存量数据需要发送无法立即发起 FIN 关闭请求。需等待 B 数据全部发送完毕后再单独发送 FIN 报文因此形成四次交互。二十、RST 标志位连接异常复位RSTReset为异常复位标志位用于强制终止异常连接区别于 FIN 正常优雅关闭连接。FIN 代表主动、有序的正常断连RST 代表连接异常、无效、故障直接强制销毁连接不做任何数据缓存和收尾处理。常见场景一方已释放连接资源另一方仍持续发送数据接收方会返回 RST 报文告知对方连接已失效触发连接被重置异常。二十一、PSH 标志位强制推送缓冲区数据至应用层PSHPush推送标志位核心作用是要求对端操作系统立即通知应用层取走接收缓冲区数据将阻塞等待的进程移入运行队列无需等待缓冲区积攒数据。操作系统默认存在数据积攒策略为了减少频繁系统调用、提升传输效率系统通常会积攒接收缓冲区数据至低水位线后才通知应用层读取数据这会带来轻微的读取延迟。而 PSH 标志位可以直接绕过该延迟机制触发即时交付。PSH 核心工作原理发送方将报文 PSH 置 1 后接收方协议栈解析到该标志会立即刷新接收缓冲区不再等待数据积攒主动唤醒阻塞在读取操作的应用进程将缓冲区数据立即交付给上层应用。典型应用场景日常使用的 Xshell、SecureCRT 等终端工具提交操作指令、敲击回车执行命令时都会在 TCP 报文中置位 PSH强制服务端系统尽快解析、响应命令避免指令因缓冲区积攒机制出现卡顿、延迟。关键补充说明PSH 仅负责改变进程就绪状态、触发数据交付无法解决应用层代码问题。若应用层存在死循环、阻塞卡顿、不主动读取数据等程序 Bug即便 PSH 置位数据也无法被正常读取生效。二十二、URG 标志位与紧急指针带外紧急数据插队机制URGUrgent紧急标志位是 TCP 实现**带外数据紧急数据**的核心开关配合 16 位紧急指针字段工作用于实现关键控制数据优先处理。22.1 核心定义与字段关系URG 标志位是紧急指针的有效性开关URG1 时紧急指针字段生效URG0 时直接忽略紧急指针字段。紧急指针的本质基于 TCP 字节流的序号体系标识字节流中特定偏移位置指向需要优先处理的紧急数据尾端。常规场景下TCP 紧急数据仅生效单个字节实现极简、高效的紧急指令传输。序号与偏移量逻辑TCP 发送缓冲区可逻辑视为有序字节数组每一个字节都拥有独立序号紧急指针依托全局序号计算偏移量精准定位紧急数据位置不受普通数据传输顺序影响。22.2 带外数据收发实现TCP 紧急数据为专属带外数据收发需要应用层接口配合无法通过普通读写接口处理发送端调用send()接口并携带MSG_OOB标志系统自动置位报文 URG 标志并填充紧急指针偏移接收端优先通过异常就绪检测带外数据再调用recv()搭配MSG_OOB标志单独读取紧急数据22.3 典型应用场景与现代替代方案核心业务价值解决 TCP 按序传输导致的控制指令排队失效问题。例如大文件持续传输场景中暂停、取消、终止等控制指令若跟随普通数据有序排队会出现指令延迟失效。通过 URG 紧急机制可让控制指令插队优先处理不被海量业务数据阻塞。现代开发替代方案URG 紧急指针机制存在功能局限、兼容性差、调试困难等问题。目前主流开发方案为双连接分离设计单独建立一条轻量 TCP 连接传输控制命令主连接专注传输业务数据彻底规避带外数据的机制缺陷稳定性远优于原生 URG 机制。二十三、内核视角下的 TCP 连接TCP 连接并非抽象的通信链路而是 Linux 内核中一系列具象的数据结构与状态集合。内核中 TCP 连接的层级结构如下应用程序 ↓ socket文件描述符 ↓ struct socket通用套接字结构 ↓ struct sock网络层套接字结构 ↓ struct tcp_sockTCP专属核心结构 ↓ 维护连接状态、IP端口、序号、队列、定时器等核心信息建立 TCP 连接的本质是内核初始化全套 TCP 数据结构、分配内核资源、维护双向通信状态的过程因此 TCP 面向连接的特性会产生固定的内核资源开销。二十四、TCP 可靠传输的本质原理TCP 的可靠传输并非保证网络链路绝对无丢包、无异常而是通过机制兜底确保数据最终可靠交付。TCP 可靠性核心逻辑发送数据 ↓ 启动超时计时器等待对方ACK应答 ↓ 收到ACK确认数据交付成功结束本轮传输 ↓ 未收到ACK超时触发重传机制重新发送数据简言之TCP 通过 ACK 确认成功交付通过超时重传弥补网络异常最终实现数据可靠传输。二十五、ACK 丢失的场景容错逻辑网络中存在大量“数据送达、ACK 丢失”的场景发送方无法区分“数据丢失”和“ACK 丢失”A B 数据报文 ────────────────────────→ B成功接收数据 ↓ B发送ACK应答 ←──────────── ACK报文丢失对 A 而言两种场景的表现完全一致未收到 ACK 应答。因此 TCP 统一采用超时重传策略处理同时依托序号机制规避重复数据问题。重传数据到达后接收方通过序号识别重复报文直接丢弃不影响数据一致性。二十六、TCP 报文字段与核心机制全局串联结合全文内容可将 TCP 所有核心机制与报文字段一一对应形成完整知识闭环源端口 / 目的端口 ↓ 精准匹配连接与应用 32位序号 ↓ 数据去重 乱序重组 32位确认序号 ↓ 累积确认机制 ↓ 同步双方传输进度 首部长度 ↓ 区分报头与数据边界 标志位SYN/ACK/FIN/RST/PSH/URG ↓ 管理连接建立、应答、断开、异常复位、数据推送、紧急插队 窗口大小 ↓ 流量控制 ↓ 匹配收发双方传输速率 数据段 ↓ 承载业务字节流TCP 核心学习主线报文结构 → 序号与确认机制 → 重传容错 → 流量控制 → 标志位连接管理。所有高级特性滑动窗口、拥塞控制、快速重传、状态机等均基于这套基础报文结构延伸扩展。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进