ZeroOne AI
← 返回文章列表

深入理解TCP协议(一):TCP报文格式详解

👁 6
分类:通讯协议

本文详解TCP报文格式:从TCP协议四大特点(面向连接、可靠性、面向字节流、全双工)出发,逐字段剖析TCP首部——源/目的端口、序号与确认序号、4位首部长度、16位窗口大小、六大标志位(SYN/ACK/FIN/RST/PSH/URG)、紧急指针、校验和,以及MSS、窗口扩大、时间戳、SACK等选项字段,是理解TCP可靠传输与流量控制机制的基础。

一、TCP 协议是什么

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接、具有可靠性、面向字节流的传输层通信协议,负责在网络中两个应用程序之间可靠地传输数据。

TCP 位于 OSI 七层模型(或 TCP/IP 四层模型)的传输层,它的核心职责是:完成进程与进程之间的数据传输、保证数据可靠到达、保证数据到达的顺序正确。它不负责主机定位与寻址——那是网络层 IP 协议的工作。

TCP 协议的四大核心特点

特点含义关键影响
面向连接通信之前必须先建立连接连接建立后双方维护通信状态,再进行数据通信(即三次握手,后续章节详解)
可靠性无论底层 IP 网络如何丢包、乱序,TCP 都尽可能保证应用层收到的数据完整、有序依靠序号、确认应答、超时重传、滑动窗口、拥塞控制等机制实现
面向字节流不关心应用层一次发送多少数据,数据何时发、发多少、丢失怎么办全由操作系统基于 TCP 决定TCP 没有消息边界,应用层需自行处理粘包/拆包问题
全双工通信连接建立后,双方可以同时发送数据收发方向独立,各自拥有发送缓冲区和接收缓冲区,这也是关闭连接需要四次挥手的原因

二、TCP 报文格式总览

TCP 报文由**报头(首部)有效载荷(数据)**两部分组成。TCP 首部最小为 20 字节,当携带选项字段时最大可达 60 字节。各字段的作用如下表所示:

字段位宽作用
源端口号16 位标识发送端主机上绑定该连接的网络进程
目的端口号16 位标识接收端主机上接收数据的网络进程,用于分用
序号32 位标识本报文携带数据的起始字节位置,解决乱序问题
确认序号32 位表示接收方已收到指定序号之前的所有数据,下一次希望接收的数据序号
首部长度(数据偏移)4 位指明 TCP 首部的长度,用于报头与有效载荷的分离
保留位6 位保留未用,置 0
标志位6 位标识 TCP 报文的类型与连接状态(SYN/ACK/FIN/RST/PSH/URG)
窗口大小16 位接收方通告自身接收缓冲区剩余空间,用于流量控制
校验和16 位检测报文在传输过程中是否发生数据损坏
紧急指针16 位定位紧急数据在字节流中的偏移位置(仅 URG=1 时有效)
选项字段可变长度扩展 TCP 功能,如 MSS、窗口扩大因子、时间戳、SACK 等

三、端口号:源端口与目的端口

16 位源端口号用于表明发送端主机网络进程绑定的端口号。当对端处理完请求并给予响应时,会根据源端口号将数据交付给发起请求的那个网络进程。

16 位目的端口号则用于"分用"(Demultiplexing):操作系统收到 TCP 报文后,根据目的端口号找到本地绑定该端口的目标进程,将应用层数据交付给它。

这里需要理解两个关键动作:

4 位首部长度的巧妙设计

4 位首部长度字段的取值范围是 [0, 15],而 TCP 首部即使不含选项字段,最小也有 20 字节,看起来 4 位根本不够表示。其实 TCP 协议规定:该字段的值 × 4 = TCP 首部的实际长度。因此它的实际表示范围是 [0, 60] 字节,完全可以正确表示 TCP 首部的大小(20~60 字节),从而完成报头与有效载荷的分离。

四、序号与确认序号

4.1 理解可靠性的本质:确认应答机制

当客户端发送的数据被服务器成功接收后,服务器会通过应答报文(ACK)告知客户端"已经收到哪些数据"。这里有个重要的约定:不对应答再做应答,否则就会出现无限套娃。

那如果应答丢失了怎么办?TCP 依靠超时重传机制解决(下一章节详解)。这里先建立对可靠性的准确理解:

  1. 客户端收到应答,可以保证服务器一定收到了客户端发送的 TCP 报文;
  2. 客户端没有收到应答的报文,无法保证服务器一定收到;
  3. TCP 并不保证每个应答报文都一定到达,但通过序号和确认序号记录传输状态,即使应答丢失,也能通过重传机制保证数据最终可靠到达。

4.2 为什么需要两个序号?

TCP 是全双工通信,双方可以同时发送数据。例如:

双方都需要记录自己发送的数据编号,同时也需要知道对方发送的数据是否被成功接收。因此 TCP 首部设计了两个字段:

字段含义
序号表示自己发送的数据编号
确认序号表示已经成功接收到对方的数据编号

只用一个序号是不行的:一个序号无法同时记录"当前发送方发送的数据编号"和"当前发送方已经收到的数据编号",也就无法同时维护两个独立方向的数据传输状态。两个序号存在的根本原因,是 TCP 需要同时维护双方的数据传输状态,从而实现可靠的全双工通信

补充:序号和确认序号并不是用来区分报文类型的(报文类型由标志位表示),虽然从理论上可以用序号区分应答报文和数据报文,但没有必要。

4.3 确认序号的取值规则

确认序号表示:接收方已经收到指定序号之前的所有数据,下一次希望接收的数据序号

举例:发送方发送序号 = 100、数据长度 = 500 的报文,接收方收到后返回的确认序号 = 600。

4.4 捎带确认机制(附加优势)

一个 TCP 报文可以同时完成两件事:发送自己的数据 + 确认收到的数据。例如服务器在回答客户端问题时,同时携带自己的数据:

这种同时包含有效序号和有效确认序号的报文被称为捎带应答,它减少了额外 ACK 报文的发送,提高了网络通信效率。

五、窗口大小与流量控制

应用层调用 read/recv 获取网络数据,并不是直接从网卡读取,而是由操作系统通过协议栈解包、分用后,将有效载荷拷贝到内核级 TCP 接收缓冲区,应用层再从接收缓冲区取数据。

计算机内存资源有限,TCP 接收缓冲区有大小限制。假设服务器以 100MB/s 的速度发送数据,而客户端应用处理速度只有 10MB/s,大量数据就会不断堆积在客户端接收缓冲区。当缓冲区空间不足时,发送方仍继续发送,接收方只能丢弃,造成大量无效传输和资源浪费——虽然重传机制能保证最终可靠,但会严重降低效率。

因此 TCP 引入流量控制机制,通过报头中的 16 位窗口大小字段解决:

六、标志位详解

TCP 首部的标志位本质就是比特位:为 1 时有效,为 0 时无效。序号、确认序号、窗口大小解决的是"数据传了多少、传到哪里"的问题,而连接建立、关闭、确认、异常等特殊状态,则需要标志位来描述。

标志位名称含义
SYNSynchronize请求建立连接
ACKAcknowledgment确认应答,表明确认序号字段有效
FINFinish请求关闭连接
RSTReset重置连接(连接异常时直接终止)
PSHPush提醒接收方尽快将数据交付给应用层
URGUrgent紧急数据标志,表明报文包含紧急数据

其中 SYN、ACK、FIN 是 TCP 中最重要的三个标志位

6.1 ACK 标志位

ACK 表示当前报文中的确认序号字段是否有效。例如 ACK=1、ack=1000,表示"确认序号有效,已经收到对方序号 1000 之前的数据"。TCP 通信过程中,大部分数据报文都会携带 ACK。

6.2 SYN 标志位

SYN 表示请求建立 TCP 连接。客户端发送 SYN=1 表示"我要和你建立连接",服务器收到后回复 SYN=1、ACK=1,表示"我同意建立连接,并确认收到你的请求"。

6.3 FIN 标志位

FIN 表示请求关闭 TCP 连接。客户端发送 FIN=1 表示"我的数据发送完毕,希望关闭连接",服务器收到后回复 ACK=1 确认收到关闭请求,之后双方分别关闭自己的发送方向。

6.4 RST 标志位

RST 表示重置 TCP 连接。当连接出现异常(连接不存在、端口没有监听、收到无法处理的数据)时,TCP 可以直接发送 RST 报文终止连接。例如客户端 connect 一个不存在的端口,服务器会返回 RST=1。

6.5 PSH 标志位

PSH 表示希望接收方立即将数据交付给应用层。正常情况下数据到达后先存放在接收缓冲区,当 PSH 被设置时,TCP 会提示接收方"这部分数据应该尽快交给应用程序"。不过在现代操作系统中,PSH 的实际影响已不像早期网络那么明显。

6.6 URG 标志位

URG 表示当前 TCP 报文包含紧急数据。当 URG=1 时,紧急指针字段有效,用于告诉接收方有部分数据需要优先处理。不过现代网络编程中实际应用非常少。

七、16 位紧急指针

紧急指针用于表示 TCP 报文中紧急数据的位置,只有当 URG 标志位为 1 时才有效

为什么需要紧急指针?正常情况下 TCP 按字节流顺序传输数据(A→B→C→D→E→F→G),接收方按顺序读取。但某些特殊场景下,发送方希望某部分数据被优先处理。例如用户远程操作服务器时,普通输入是 ls、cd /home 等命令,而 Ctrl+C 需要被优先处理,不能等待前面的普通数据全部处理完成。

紧急指针如何工作?假设发送的数据是 A B C D E F,其中 D 是紧急数据,则 TCP 报文中设置 URG=1、Urgent Pointer=3,表示"从当前序号开始偏移 3 个字节的位置存在紧急数据",接收方据此定位并优先处理。

在 Linux 等现代操作系统中,TCP 紧急数据通常按 1 字节带外数据(OOB Data)处理,应用层可利用这 1 字节自行定义含义(如约定不同数值表示不同的紧急事件)。为什么现在很少使用?主要有两个原因:

  1. 应用层通常自己设计优先级机制(消息类型字段、优先级字段、控制消息),更灵活可控;
  2. TCP 紧急数据机制在不同操作系统上的实现存在差异。

因此实际开发中,更多使用"应用层协议 + 消息优先级设计"来实现类似功能。

八、16 位校验和

校验和用于检测 TCP 报文在传输过程中是否发生数据损坏。发送端根据 TCP 首部、数据以及相关的 IP 信息计算出一个 16 位校验和值;接收端收到报文后按同样的规则重新计算并比较。如果计算结果不一致,说明报文很可能在传输中损坏,接收端直接将该报文丢弃。

九、选项字段

TCP 首部最小长度为 20 字节,但设计时预留了可变长度的选项字段,用于扩展 TCP 的功能。由于选项字段长度不固定,TCP 通过**数据偏移(首部长度)**字段表示首部实际长度:

接收方通过数据偏移字段就能知道 TCP 数据从哪里开始。常见选项如下:

选项全称作用
MSSMaximum Segment Size最大报文段长度,通信双方告知对方自己能接收的最大 TCP 数据长度,避免分段过大
窗口扩大因子Window Scale扩展 16 位窗口字段的表示范围,突破 65535 字节限制,适配高带宽网络
时间戳Timestamp计算 RTT(往返时间),防止旧数据包影响新连接
SACKSelective ACK选择确认,告诉发送方具体哪些数据已收到、哪些缺失,减少不必要的重传

以 MSS 为例:客户端发送 SYN 时携带 MSS=1460,表示"我希望你发送给我的 TCP 数据部分最大为 1460 字节"。以 SACK 为例:默认 TCP 的 ACK 是累计确认,收到 1、2、3、5 缺少 4 时只能告诉发送方 ack=4;而 SACK 可以精确告知"1~3 已收到、5 已收到、4 缺失",从而减少不必要的重传。

十、总结

TCP 报文格式是理解整个 TCP 协议的基础。本文核心要点:

掌握了报文格式,下一篇我们将深入 TCP 的可靠传输与高效通信机制:确认应答、超时重传、滑动窗口、流量控制、拥塞控制、延迟应答与捎带应答是如何协同工作,让 TCP 既可靠又高效的。

SEO 关键词

TCP协议、TCP报文格式、TCP首部、TCP标志位、SYN、ACK、FIN、RST、TCP序号、确认序号、窗口大小、流量控制、MSS、SACK、传输层协议、网络协议详解

评论(0