TCP协议
基本定义
传输控制协议(Transmission Control Protocol)
-
OSI模型第四层(传输层)
-
面向连接的可靠字节流服务
- 面向连接(连接建立与释放,只能一对一,不能像UDP一对多)
- 可靠传输(确认应答 + 超时重传 + 校验 + 有序传输 + 流量控制 + 拥塞控制)
- 面向字节流(数据以字节流方式发送,不保留消息边界。且有序的,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃)
-
全双工通信模式(双方可以同时发送和接收)
-
RFC 793标准定义
什么是连接
报文格式
1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2| Source Port(16bit) | Destination Port(16bit) |
3+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4| Sequence Number(32bit) |
5+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6| Acknowledgment Number(32bit) |
7+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8| Data | |C|E|U|A|P|R|S|F| |
9| Offset | Rsvd |W|C|R|C|S|S|Y|I| Window |
10| (4bit) |(4bit) |R|E|G|K|H|T|N|N| (16bit) |
11+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12| Checksum(16bit) | Urgent Pointer(16bit) |
13+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14| Options | Padding |
15+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
TCP 首部最小 20 字节,最大 60 字节(含可选项)
字段 | 长度 | 描述 |
---|---|---|
源端口(Source Port) | 16 位 | 源端口号 |
目的端口(Destination Port) | 16 位 | 目标端口号 |
序列号(Sequence Number) | 32 位 | 数据字节流的起始序号,用来解决网络包乱序问题 |
确认号(Acknowledgment Number) | 32 位 | 期望接收的下一个字节的序号,用来解决丢包的问题 |
数据偏移(Data Offset) | 4 位 | 首部长度(以 4 字节为单位,最大15 * 4 = 60 B) |
保留 | 4 位 | 保留位,未使用 |
控制位(Flags) | 8 位 | 各类控制标志 |
窗口大小(Window Size) | 16 位 | 表示接收方缓冲区剩余容量 |
校验和(Checksum) | 16 位 | 整个 TCP 报文段的 CRC 校验值 |
紧急指针(Urgent Pointer) | 16 位 | 紧急数据的偏移量(配合 URG 位使用) |
可选项(Options) | 可变 | 例如时间戳、窗口扩大等 |
控制位 | 作用 |
---|---|
CWR | Congestion Window Reduced |
ECE | ECN-Echo |
URG | 紧急指针有效 |
ACK | 确认号有效,除了最初建立连接时的 SYN 包之外该位必须设置为 1 |
PSH | 提示尽快推送数据给应用层 |
RST | 复位连接,TCP 连接中出现异常必须强制断开连接(复位报文段) |
SYN | 同步序列号,用于建立连接(同步报文段) |
FIN | 终止连接(结束报文段) |
连接管理
状态机
(包含11个状态转换节点) LISTEN 监听连接请求
- SYN-SENT:发送了 SYN,等待对方确认 SYN_RCVD
- SYN-RECEIVED:收到对方 SYN,已发送 SYN+ACK ESTABLISHED
- ESTABLISHED:连接已建立 FIN_WAIT_1 FIN_WAIT_2 TIME_WAIT
- FIN-WAIT-1/2、CLOSE-WAIT:连接关闭过程中的中间状态
- TIME-WAIT:主动关闭方等待 2MSL CLOSED
- CLOSED:连接关闭完成
连接建立
三次握手(Three-way Handshake)
- Client → Server: [SYN] Seq=x
- Server → Client: [SYN+ACK] Seq=y Ack=x+1
- Client → Server: [ACK] Seq=x+1 Ack=y+1
完成后,双方进入 ESTABLISHED
状态,可以开始传输数据。
第一次握手丢失
第二次握手丢失
第三次握手丢失
连接释放
四次挥手(Four-way Handshake)
- HostA → HostB: [FIN] Seq=u
- HostB → HostA: [ACK] Ack=u+1
- HostB → HostA: [FIN+ACK] Seq=v
- HostA → HostB: [ACK] Ack=v+1
客户端进入 TIME_WAIT
状态等待 2MSL(最大报文生存时间)后关闭。
第一次挥手丢失
第二次挥手丢失
第三次挥手丢失
第四次挥手丢失
可靠传输机制
序列号与确认号
每个 TCP 报文段都有序列号,确认号用于应答已收到的数据字节。 序列号分配:每个字节唯一编号
累积确认
ACK=N表示N之前所有数据已接收
超时重传
超时重传(Retransmission Timeout, RTO) 动态计算RTT,指数退避重传
数据校验和
对 TCP 首部、数据和伪首部(包括 IP 地址等)计算校验和,防止数据损坏。
流量控制
流量控制(Flow Control)利用窗口机制(Window Size)来控制发送方速率,防止接收方缓冲区溢出。
- 接收窗口动态变化,根据接收能力调整。
- 发送窗口由 [已确认序号, 未确认序号, 可用窗口大小] 决定。 滑动窗口动态调整: 发送窗口 = min(拥塞窗口, 接收方通告窗口) 窗口缩放选项支持扩大至1GB
拥塞控制
用于控制网络中的数据流量,防止过载。
常用算法:
- 慢开始(Slow Start)
- 初始拥塞窗口 cwnd=1,指数增长(每收到 ACK cwnd += 1)
- 拥塞避免(Congestion Avoidance)
- cwnd 达到阈值后线性增长
- 快重传(Fast Retransmit)
- 连续收到 3 个重复 ACK,立即重传缺失报文
- 快恢复(Fast Recovery)
- 阈值减半,cwnd 设置为阈值,避免重回慢启动阶段
拥塞窗口(cwnd)
- 发送方根据 cwnd 和接收窗口大小控制实际发送量:
Effective Window = min(cwnd, rwnd)
慢启动 → 拥塞避免 → 快速重传/快速恢复 经典算法:Tahoe/Reno/NewReno/CUBIC
关键算法
Nagle算法:减少小包发送 Karn算法:处理重传RTT测量 SACK选项:选择性确认机制
典型应用
- Web(HTTP/HTTPS)
- 邮件(SMTP/POP3/IMAP)
- 文件传输(FTP)
- SSH、Telnet 等远程登录
HTTP/HTTPS | SSH | SMTP | 数据库连接 需可靠传输的场景优先选择TCP
抓包分析要点
SYN/FIN标志位 | 序列号连续性 | 窗口大小变化 重传计数 | 选项字段解析 | RTT计算
调优参数
net.ipv4.tcp_keepalive_time = 7200 net.ipv4.tcp_max_syn_backlog = 1024 net.ipv4.tcp_slow_start_after_idle = 0
常见攻击与防御
- SYN Flood 攻击:伪造大量 SYN 请求,占用连接资源
- 防御方法:SYN Cookie、加速超时、限制半连接数
- RST 注入攻击:伪造 RST 报文断开连接
- TCP 会话劫持:猜测序列号篡改连接
与 UDP 对比
特性 | TCP | UDP |
---|---|---|
是否连接 | 是 | 否 |
可靠性 | 可靠(重传 + 确认) | 不可靠 |
顺序性 | 有序传输 | 可能乱序 |
开销 | 较大 | 小 |
适用场景 | 文件传输、HTTP | 视频、DNS、VoIP |
参考协议文档:RFC 793(TCP),RFC 1122,RFC 5681(拥塞控制)
UDP和TCP可以使用同一个端口吗?
存在问题
队头阻塞
队头阻塞(Head-of-Line Blocking,HOL Blocking)是计算机网络中的一个经典问题,指在顺序处理的数据流中,一个数据包的延迟或丢失会导致后续数据无法被及时处理。这种现象类似于堵车时,一辆车抛锚会阻塞后面所有车辆。根据发生位置不同,队头阻塞可分为传输层队头阻塞和应用层队头阻塞。
- 传输层队头阻塞(TCP 的典型问题) 问题根源 TCP 的可靠性机制: TCP 是面向字节流的协议,所有数据必须按顺序交付。假设发送方发送了数据包 A、B、C,若包 B 丢失,即使包 A 和 C 已到达接收方,接收方也无法将包 C 传递给应用层,必须等待包 B 重传成功。
单一路径的串行处理: TCP 将所有数据视为单一连续流,即使通过多线程或分片(如 HTTP/1.1 的管道化)发送,丢失一个包仍会阻塞整个连接。
示例场景 网页加载: 一个网页需要加载 10 个资源(图片、CSS、JS),若某个资源对应的 TCP 包丢失,即使其他资源已到达浏览器,也会被阻塞,直到丢失包重传完成。
视频流传输: 视频的 I 帧(关键帧)丢失会导致后续 P 帧无法解码,即使后续帧已到达客户端,画面仍会卡顿。
QUIC 的解决方案 多路复用流(Multiplexed Streams): QUIC 允许在单个连接中创建多个独立的流(Stream),每个流独立处理数据包。若流 1 的包丢失,流 2、3 的数据仍可继续处理。
流的隔离性:每个流有自己的序号和可靠性机制,互不影响。
示例:网页中的 CSS 和图片分属不同流,CSS 流丢包不会阻塞图片流的传输。
- 应用层队头阻塞(HTTP/1.1 的典型问题) HTTP/1.1 的管道化(Pipelining)缺陷 请求-响应必须按序处理: 客户端通过一个 TCP 连接发送多个 HTTP 请求(如请求 HTML、CSS、JS),但服务器必须按顺序返回响应。若第一个响应延迟,后续所有响应都会被阻塞。
浏览器实际禁用管道化: 由于队头阻塞问题,主流浏览器默认禁用 HTTP/1.1 管道化,转而使用多个 TCP 连接并行请求,但这增加了连接开销。
HTTP/2 的改进与局限 多路复用(Multiplexing): HTTP/2 允许在单个 TCP 连接上并行传输多个请求和响应(通过分帧和流 ID),解决了应用层的队头阻塞。例如,一个大的 JS 文件响应不会阻塞小的 CSS 文件响应。
仍受限于 TCP 的传输层队头阻塞: 若底层 TCP 包丢失,HTTP/2 的所有流仍会被阻塞,因为 TCP 需要保证数据按序到达。
- QUIC 如何彻底解决队头阻塞? QUIC 在传输层和应用层同时规避了队头阻塞:
传输层:
每个流独立处理数据包,丢失的包仅影响对应流。
示例:流 1 的包 2 丢失时,流 2 的包 3、4 仍可被处理。
应用层(HTTP/3):
HTTP/3 基于 QUIC 的多路复用流,每个资源对应一个流,彻底消除应用层依赖传输层顺序的问题。
即使某个流因丢包被阻塞,其他流仍可正常传输。
- 队头阻塞的直观对比 场景 TCP + HTTP/1.1 TCP + HTTP/2 QUIC + HTTP/3 传输层队头阻塞 严重(单流串行处理) 严重(依赖 TCP 单流) 无(多流独立处理) 应用层队头阻塞 严重(按序响应) 无(多路复用) 无(多路复用 + 多流)
- 现实中的队头阻塞案例 高延迟网络: 在卫星通信或移动网络中,TCP 丢包重传会导致整个连接卡顿,QUIC 仅影响部分流。
多资源网页: 使用 HTTP/2 的网站在 TCP 丢包时,页面加载时间可能增加 50% 以上;而 HTTP/3 可保持其他资源加载不受影响。
总结 队头阻塞本质是顺序依赖导致的性能瓶颈,分为传输层和应用层两种。
QUIC 通过多路复用和流隔离,在传输层消除了队头阻塞,而 HTTP/3 在此基础上进一步优化了应用层性能。
该设计使 QUIC 在高丢包、高延迟网络中表现显著优于 TCP,成为现代 Web 和实时通信的核心协议。