尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

《Linux 网络编程》深入理解 TCP 协议(三):TCP 报头六大标志位详解

《Linux 网络编程》深入理解 TCP 协议(三):TCP 报头六大标志位详解 小叶-duck个人主页❄️个人专栏《Data-Structure-Learning》《C入门到进阶自我学习过程记录》《Linux系统从入门到实践》《Linux网络从入门到实践》《Qt 方寸极境》 《MySQL》✨未择之路不须回头已择之路纵是荆棘遍野亦作花海遨游目录前言一、TCP 报头标志位字段详解1.1 标志位本质与内核结构体定义1.2 ACK 标志位确认标志1.2.1 ACK 是什么1.2.2 ACK 在 TCP 体系中的意义1.3 SYN 标志位同步标志1.3.1 SYN 标志基础1.3.2 初识三次握手流程1.4 FIN 标志位结束标志1.4.1 FIN 标志基础1.4.2 初识四次挥手流程1.5 RST 标志位复位连接的 “紧急刹车”1.5.1 c1.6 PSH 标志位催促数据交付的 “加急快递”1.6.1 PSH 标志基础1.6.2 PSH 的工作机制1.6.3 边界与局限PSH 不是万能的强制读取指令1.7 URG 标志位优先处理的 “绿色通道 ”1.7.1 URG 标志基础1.7.2 TCP 报头 16 位紧急指针原理1.7.3 实战坑点BSD Socket MSG_OOB 实现问题1.7.4 URG、PSH、RST 简单区分结束语前言在上一篇文章中我们解析了 TCP 首部长度字段、确认应答和超时重传搭建起 TCP 可靠传输的基础框架。而 TCP 报文头部还有一组十分关键的控制字段 —— 六大标志位连接建立、数据推送、紧急指令、连接断开等全部核心行为都依靠它们来驱动。SYN、ACK、FIN、RST、PSH、URG 各自承担不同职责很多网络编程面试题、线上连接异常问题根源都在于对标志位理解不到位。本文将继续顺着 TCP 协议的学习脉络逐个拆解六大标志位的含义、工作场景结合 Linux 内核结构体定义讲解三次握手、四次挥手的基础流程同时区分 PSH 推送提醒与 URG 紧急带外数据的差异分析 Socket 接口实现中紧急数据的实战坑点。全部内容结合协议规范与内核行为兼顾原理理解和面试实战。一、TCP 报头标志位字段详解1.1 标志位本质与内核结构体定义TCP 报头一共定义 8 个标志位日常协议交互中重点使用其中 6 个。每一个标志位仅占用1 比特是 C 语言位段的典型应用。标志位的核心作用就是区分报文类型告诉接收端该如何处理当前收到的 TCP 报文。建立连接、断开连接、数据应答、紧急数据等不同类型报文就是依靠将对应标志位置 1 来完成类型区分。我们来看 Linux 内核tcphdr结构体里标志位的定义源码位于include/linux/tcp.hstruct tcphdr { __be16 source; __be16 dest; __be32 seq; __be32 ack_seq; #if defined(__LITTLE_ENDIAN_BITFIELD) __u16 res1:4, // 保留位4位 doff:4, // 4位首部长度 fin:1, // FIN标志关闭连接 syn:1, // SYN标志建立连接 rst:1, // RST标志重置连接 psh:1, // PSH标志推送数据 ack:1, // ACK标志确认号有效 urg:1, // URG标志紧急指针有效 ece:1, // ECE标志显式拥塞通知回显 cwr:1; // CWR标志拥塞窗口减小 #elif defined(__BIG_ENDIAN_BITFIELD) __u16 doff:4, res1:4, cwr:1, ece:1, urg:1, ack:1, psh:1, rst:1, syn:1, fin:1; #else #error Adjust your asm/byteorder.h defines #endif __be16 window; __sum16 check; __be16 urg_ptr; };补充说明这里使用条件编译__LITTLE_ENDIAN_BITFIELD是因为大小端平台下位段在内存排布顺序不一样内核通过这种写法保证不同 CPU 架构下标志位定义都能正常解析。1.2 ACK 标志位确认标志1.2.1 ACK 是什么ACK 全称acknowledgment本质是确认序号字段的开关。当ACK0代表这份报文不是应答报文TCP 头部的 32 位确认序号失去意义内核会直接忽略 ack_seq 字段。当ACK1代表报文中确认序号字段有效接收端内核必须读取并解析确认序号代表这个报文携带了对之前收到数据的确认。除连接建立阶段最初的 SYN 报文之外后续 TCP 传输过程中几乎所有报文ACK 标志都会置为 1。即便当前报文主要用来发送业务数据TCP 也会顺便捎带上对过往数据的确认这就是 TCP 的捎带应答机制。TCP 是全双工对等通信通信双方地位完全平等两端都拥有独立的发送缓冲区与接收缓冲区任意一方都可以主动发送数据同时也要承担应答对方数据的任务ACK 标志就是实现双向应答的基础。对比HTTP 属于非对等的主从架构客户端主动发起请求服务端被动响应而 TCP 两端没有绝对的客户端、服务端身份限制连接建立后两端对等。1.2.2 ACK 在 TCP 体系中的意义ACK 标志是六个标志里最核心的一个。网络传输存在丢包、乱序等不可靠问题TCP 依靠确认应答 超时重传实现可靠传输而全双工、流水线并行传输场景下TCP 依靠序号、确认序号与 ACK 标志完成对数据的确认、推进接收窗口形成整套可靠传输闭环。1.3 SYN 标志位同步标志1.3.1 SYN 标志基础作用请求建立连接。使用场景在 TCP 三次握手的前两个报文中使用。含义当SYN1时表示这是一个连接请求报文。TCP 属于面向连接的协议必须先建立连接才能开始传输业务数据连接建立流程依靠 SYN 标志完成三次握手。1.3.2 初识三次握手流程第一次握手客户端向服务端发送 SYN 报文无应用数据仅 TCP 报头请求建立连接第二次握手服务端收到 SYN 后返回 SYNACK 合并报文既确认客户端建连意愿也表达自身建连意愿第三次握手客户端收到 SYNACK 后返回 ACK 应答报文确认服务端意愿双方连接进入 ESTABLISHED 已建立状态。注意通信过程中不会单独传输 SYN、ACK 比特位只是 TCP 报头中把对应标志位置 1底层依旧是标准 TCP 报文传输。本篇文章仅做初识介绍后续在 TCP 连接管理章节会深入讲解连接相关系统调用、三次握手的本质以及为什么需要三次握手还有 “逻辑上本质是四次握手” 这一知识点。1.4 FIN 标志位结束标志1.4.1 FIN 标志基础作用通知对方本端要关闭连接。使用场景在 TCP 四次挥手的过程中使用。含义当FIN1时表示本端已经没有数据要发送了请求关闭连接。TCP 是全双工通信读写两个方向通道相互独立。数据传输完成后依靠 FIN 标志位断开 TCP 连接标准流程为四次挥手双方需要各自关闭属于自己的读写通道。1.4.2 初识四次挥手流程第一次挥手主动关闭方调用 close发送 FIN 报文告知对方本端不再发送数据第二次挥手被动关闭端返回 ACK 应答确认收到关闭请求此时被动端仍然可以继续发送缓冲区里剩余的数据第三次挥手被动端数据全部发送完毕后发送 FIN 报文告知主动端自身也准备关闭发送通道第四次挥手主动端返回 ACK 应答确认关闭。主动端会进入 TIME_WAIT 状态等待足够时长之后双方连接彻底释放变为 CLOSED 状态。涉及的状态流转FIN_WAIT1、FIN_WAIT2、CLOSE_WAIT、LAST_ACK、TIME_WAIT、CLOSED。注意通信过程中不会单独传输 FIN、ACK 比特位只是 TCP 报头中把对应标志位置 1底层依旧是标准 TCP 报文传输。本节仅做初识介绍后续 TCP 连接管理章节会重新深入剖析四次挥手讲解握手只需要三次而挥手需要四次的根本原因以及为什么三次握手可以看作合并后的四次握手但四次挥手一般情况无法简化合并成三次挥手。1.5 RST 标志位复位连接的 “紧急刹车”1.5.1 c作用强制复位、中断 TCP 连接相当于连接的紧急刹车。使用场景两端连接状态不一致、连接发生异常时。含义当RST1代表告知对方直接终止本次连接无需走四次挥手的正常关闭流程。RST 全称 Reset 复位携带 RST 标识的报文叫做复位报文段核心目标是解决通信双方连接状态不一致的问题。三次握手有一处天然短板最后一个 ACK 报文没有对应的应答确认机制容易出现两端认知不一致。典型场景三次握手最后一个 ACK 报文丢失客户端视角发出最后一个 ACK直接切换到 ESTABLISHED 状态认定连接成功能够发送业务数据。服务端视角ACK 报文丢失服务端停留在 SYN_RCVD 状态判定握手尚未完成连接没有建立。此时客户端继续发送业务数据服务端会判定报文非法直接回复 RST 复位报文通知客户端连接异常需要重新发起连接建立。重要特性RST 报文不需要接收方返回 ACK 确认。发送方发出 RST 之后直接断开连接接收方收到 RST 报文会立刻释放连接资源不会进入 TIME_WAIT 状态。RST 报文作用连接异常、两端状态不一致时强制重置连接重新握手。客户端 服务端 SYN --------- --------- SYNACK ACK --------- 【ACK丢失】 客户端连接建立成功 服务端握手未完成 客户端发业务数据 --------- --------- RST 客户端重新建立连接1.6 PSH 标志位催促数据交付的 “加急快递”1.6.1 PSH 标志基础作用提醒接收端应用程序尽快从 TCP 缓冲区读取数据降低端到端的交互延迟并非强制指令。使用场景交互型连接、小数据需要及时交付的场景典型如 SSH、Telnet 远程终端。含义当PSH1发送方告知接收方希望收到报文后尽快把缓冲区数据交付给应用层不用等待缓冲区填满、达到水位线再交付。PSH 全称 Push可以理解为 TCP 里的加急提醒。它不会建立连接、确认报文或者关闭连接只用来调整数据交付的时机。TCP 为提升传输效率默认会合并小包发送接收端也会等待缓冲区积攒一定数据量后再一次性交给应用层。这种策略适合大批量文件传输但交互式命令场景会产生明显延迟PSH 标志就是用来解决这类延迟问题。1.6.2 PSH 的工作机制发送方设置 PSH 标志时包含两层意图发送端立刻发送当前缓冲区的数据不再攒包等待接收端收到带 PSH 的报文后尝试尽快唤醒等待数据的应用进程把缓冲区数据交付给应用层。重点PSH只是提醒不能强制接收方读取缓冲区数据。数据交付最终由操作系统 TCP 协议栈调度。收到 PSH 报文内核只会把对应数据标记为可交付状态尝试触发 read 就绪条件而非强制应用程序执行读取操作。操作系统 TCP 协议栈内部维护缓冲区水位线机制分为低水位SO_RCVLOWAT与高水位阈值。只有接收缓冲区的数据量达到低水位read、epoll 等才会判定套接字可读就绪唤醒阻塞等待的应用。PSH 的作用是临时降低这个就绪门槛协议栈可忽略低水位约束直接触发 read 就绪事件但仅仅是就绪通知不代表应用程序一定会马上读取。❌常见误解收到 PSH应用必须立刻读。PSH 仅为提醒内核仅触发就绪事件读取行为由应用代码决定。1.6.3 边界与局限PSH 不是万能的强制读取指令PSH 的所有效果都建立在应用层已经调用read或者通过 epoll/select 监听套接字事件的前提之上。如果应用程序本身没有调用 read 读取数据例如业务逻辑死循环、没有把 read 放入事件循环PSH 报文抵达 → 内核发出就绪通知 → 应用没有监听等待 → 数据持续堆积在接收缓冲区。哪怕触发低水位也没有等待的进程可以唤醒。此时无论发送多少携带 PSH 的报文都无法推动数据读取数据会一直留在内核缓冲区直到连接关闭或程序崩溃。这类问题本质属于应用程序 bug并非 TCP 协议或者发送端的问题。1.7 URG 标志位优先处理的 “绿色通道 ”1.7.1 URG 标志基础作用标识 TCP 报头内16 位紧急指针字段是否有效用来实现带外紧急数据传输给控制指令开辟优先处理通道。使用场景远程终端中断、传输任务启停控制典型例子SSH 里CtrlC中断远端程序、网盘暂停 / 取消上传指令。含义常规通信URG0紧急指针无效当URG1代表当前报文包含紧急数据接收端可以跳过普通数据流排队优先处理紧急控制信息。TCP 默认数据按序号顺序排队交付给应用层。但部分控制指令不能等待前面大批量数据处理完毕URG 标志搭配紧急指针就实现了这种带外优先处理能力。1.7.2 TCP 报头 16 位紧急指针原理紧急指针是相对于当前报文数据区起始位置的偏移量仅作用在当前这一个 TCP 报文段和全局缓冲区、整条连接的全局序号不产生关联。 规则紧急数据从当前报文数据区第一个字节开始紧急指针的数值等于紧急数据总字节长度指向紧急数据最后一个字节紧急数据区间[本报文起始序号本报文起始序号 紧急指针 − 1]区间内为紧急数据后面剩余部分属于普通数据。示例 报文起始序号1000数据区总长 100 字节紧急指针值10紧急数据区间1000 ~ 1009前 10 字节普通数据区间1010 ~ 1099后 90 字节接收端检测到URG1会优先把这一段紧急数据递交给应用层不需要在普通缓冲区排队等待。易混淆点计算紧急数据末尾序号时公式起始序号 紧急指针 −1看起来和全局序号相关但紧急指针本身只代表当前报文内部的数据长度后续报文的紧急数据由各自报文的紧急指针独立定义不会复用之前的偏移。1.7.3 实战坑点BSD Socket MSG_OOB 实现问题协议层面紧急指针由于大小是16位 bit理论可以标记最长 65535 字节的紧急数据。但 BSD Socket 的经典实现存在历史遗留问题 接收端使用MSG_OOB标记读取带外数据时只能读到紧急数据的最后一个字节紧急数据前面其余字节会混入普通数据流需要用普通 recv 读取。示例 发送方调用send(sockfd, ABCD, 4, MSG_OOB)内核生成URG1报文紧急指针 4指向字符D接收端recv(sockfd, buf, 1, MSG_OOB)仅读到DA、B、C被当作普通数据通过普通 recv 读取注意这属于 Socket 接口实现层面的历史遗留问题不是 TCP 协议本身的限制。工程开发建议尽量不依赖 TCP 紧急数据。优先采用双连接方案一条连接传输业务数据一条独立连接传输控制指令稳定性更好。1.7.4 URG、PSH、RST 简单区分URG标记带外紧急数据让控制指令优先处理开辟数据绿色通道PSH提醒内核尽快将缓冲区数据交付应用层只是交付时机的提示不区分紧急数据流RST强制立刻断开连接终止本次 TCP 会话不需要四次挥手。结束语本篇我们逐一分析了 TCP 报头里六个核心标志位从 ACK、SYN、FIN到 RST、PSH、URG梳理了它们各自的作用、底层逻辑以及对应的连接交互流程。SYN 与 FIN 支撑起连接建立与关闭的完整生命周期RST 作为异常重置手段快速释放故障连接PSH 用来通知内核尽快向上交付数据而 URG 紧急指针机制则实现了带外数据优先传输的能力。标志位是 TCP 报文的控制开关理解它们才能看懂抓包文件里的报文交互定位断连、连接重置等各类网络异常。但 TCP 协议的内容还远没有结束连接管理、滑动窗口、拥塞控制等更多核心机制会在后续文章继续展开。
返回列表