TCP 协议核心机制与性能优化深度解析

TCP/IP 与 HTTP 协议核心机制——从三次握手到 HTTPS 加密

摘要

TCP/IP 协议族是互联网的基石,理解其核心机制对每位后端工程师都至关重要。本文从 TCP 三次握手与四次挥手讲起,深入剖析流量控制、拥塞控制算法,梳理 HTTP/1.1 到 HTTP/3 的演进脉络,详细拆解 HTTPS TLS 1.3 握手过程,并提供基于 Wireshark 的抓包实战分析。全文包含大量流程图解与抓包示例。


一、TCP 三次握手与四次挥手

1.1 三次握手——建立连接

sequenceDiagram
    participant C as Client<br/>CLOSED
    participant S as Server<br/>LISTEN

    Note over C: CLOSED  SYN-SENT
    C->>S:  SYN=1, seq=x
    Note over S: LISTEN  SYN-RCVD
    S->>C:  SYN=1, ACK=1, seq=y, ack=x+1
    Note over C: SYN-SENT  ESTABLISHED
    C->>S:  ACK=1, seq=x+1, ack=y+1
    Note over S: SYN-RCVD  ESTABLISHED

握手目的:
1. 同步双方的初始序列号(ISN)
2. 协商 TCP 参数(MSS、窗口缩放因子等)
3. 验证双方收发能力正常

三次握手状态变迁:

状态 含义 所在端
CLOSED 初始关闭状态 双方
LISTEN 服务端等待连接 服务端
SYN-SENT 已发 SYN 客户端
SYN-RCVD 已收 SYN,已发 SYN+ACK 服务端
ESTABLISHED 连接建立 双方

SYN Flood 攻击原理: 客户端发送大量 SYN 但不完成第三次握手,导致服务端维护大量半连接(SYN-RCVD)队列耗尽资源。缓解手段包括 SYN Cookie、增大 tcp_max_syn_backlog 等。

# 查看 TCP 连接状态
ss -tna | head -20

# 查看半连接队列大小
sysctl net.ipv4.tcp_max_syn_backlog
# 默认 128(现代系统通常 1024)

# 启用 SYN Cookie
sysctl -w net.ipv4.tcp_syncookies=1

1.2 四次挥手——关闭连接

sequenceDiagram
    participant C as Client<br/>ESTABLISHED
    participant S as Server<br/>ESTABLISHED

    Note over C: 应用调用 close()
    Note over C: ESTABLISHED  FIN-WAIT-1
    C->>S:  FIN=1, seq=u
    Note over S: ESTABLISHED  CLOSE-WAIT
    Note over S: 应用仍可发送剩余数据
    S->>C:  ACK=1, seq=v, ack=u+1
    Note over C: FIN-WAIT-1  FIN-WAIT-2
    Note over S: 应用调用 close()
    Note over S: CLOSE-WAIT  LAST-ACK
    S->>C:  FIN=1, ACK=1, seq=w, ack=u+1
    Note over C: FIN-WAIT-2  TIME-WAIT
    C->>S:  ACK=1, seq=u+1, ack=w+1
    Note over S: LAST-ACK  CLOSED
    Note over C: TIME-WAIT (2MSL)  CLOSED

TIME-WAIT 的作用:
1. 确保最后的 ACK 被对端收到(超时重传 FIN)
2. 等待网络中残留的旧数据包过期,防止干扰新连接

为什么 TIME-WAIT 是 2MSL? MSL(Maximum Segment Lifetime,报文最大生存时间,通常 30s~2min)。等待 2MSL 实现了:发送 ACK 后留出 1MSL 等待可能的 FIN 重传 + 收到重传 FIN 后重新发送 ACK 再到对端所需的另 1MSL。

1.3 TCP Keepalive

TCP Keepalive 检测对端是否存活:

# 查看默认配置
sysctl net.ipv4.tcp_keepalive_time       # 7200s(2小时)
sysctl net.ipv4.tcp_keepalive_intvl      # 75s
sysctl net.ipv4.tcp_keepalive_probes     # 9次

即默认需要 2h + 9 × 75s ≈ 2h11min 才能发现对端死亡。生产环境通常调短:

sysctl -w net.ipv4.tcp_keepalive_time=300
sysctl -w net.ipv4.tcp_keepalive_intvl=30
sysctl -w net.ipv4.tcp_keepalive_probes=3

二、流量控制与拥塞控制

2.1 流量控制——滑动窗口

流量控制(Flow Control)解决 接收端处理能力不足 的问题,通过滑动窗口机制实现。

sequenceDiagram
    participant S as Sender
    participant R as Receiver

    Note over S: 发送窗口 = min(cwnd, rwnd)
    S->>R: 发送 1~4(窗口大小=4
    R->>R: 处理到第 2 个数据包<br/>应用层未读取缓冲数据
    R->>S: ACK=3, win=2<br/>(缓冲区满,通知窗口缩小)
    Note over S: 发送窗口缩小到 2
    S->>R: 发送 5~6
    R->>R: 应用层读取数据,缓冲区空闲
    R->>S: ACK=7, win=5
    Note over S: 窗口重新扩大

接收窗口 rwnd 的计算:

rwnd = RecvBuffer - (LastByteRcvd - LastByteRead)

/proc/sys/net/ipv4/tcp_rmem 定义了接收缓冲区的大小范围(min、default、max):

# 查看 TCP 缓冲区配置
cat /proc/sys/net/ipv4/tcp_rmem
# 4096   131072  6291456
# min=4KB, default=128KB, max=6MB

cat /proc/sys/net/ipv4/tcp_wmem
# 4096   16384   4194304
# min=4KB, default=16KB, max=4MB

窗口缩放因子(Window Scaling): TCP 头部窗口字段只有 16 位,最大 65535 字节。通过三次握手中的窗口缩放因子(/proc/sys/net/ipv4/tcp_window_scaling),可将窗口放大到 1GB 级别,适应高带宽网络。

2.2 拥塞控制

拥塞控制(Congestion Control)解决 网络链路负载能力不足 的问题,由发送方自主控制。

算法阶段 触发条件 窗口变化
慢启动(Slow Start) 连接建立 / 超时重传 每 RTT 翻倍(指数增长)
拥塞避免(Congestion Avoidance) 达到 ssthresh 每 RTT +1(线性增长)
快速重传(Fast Retransmit) 收到 3 个重复 ACK 立即重传丢失段
快速恢复(Fast Recovery) 快速重传后 ssthresh = cwnd/2, cwnd = ssthresh + 3
graph TD
    A[慢启动开始<br/>cwnd=1 MSS] --> B{发生超时?}
    B -->|"ssthresh=cwnd/2
cwnd=1"
| A B -->|"cwnd >= ssthresh"| C[拥塞避免<br/>cwnd += 1/RTT] C --> D{收到 3 <br/>重复 ACK?} D -->|"ssthresh=cwnd/2
cwnd=ssthresh+3"
| E[快速恢复] D -->|"超时"| A E --> F{收到新 ACK?} F -->|"是"| C F -->|"仍然重复 ACK"| E

三种主流拥塞控制算法:

算法 核心思想 适用场景 Linux 默认版本
Cubic 立方函数增长,RTT 无关 高带宽长链路 <= 4.18 默认
BBR 基于带宽和 RTT 测量建模 高丢包率链路 >= 4.18 可选
BBRv3 BBR 改进版,更好公平性 混合网络 >= 5.19 可选
# 查看当前拥塞控制算法
sysctl net.ipv4.tcp_congestion_control
# net.ipv4.tcp_congestion_control = bbr

# 查看可用的算法
sysctl net.ipv4.tcp_available_congestion_control
# bbr cubic reno

# 切换算法
sysctl -w net.ipv4.tcp_congestion_control=bbr

三、HTTP/1.1 / HTTP/2 / HTTP/3 演进

3.1 HTTP/1.1 —— 基础但有限

graph LR
    subgraph HTTP/1.1
        C1[Client] -->|"请求1(串行)"| S1[Server]
        C1 -->|"请求2(需等请求1完成)"| S1
        C1 -->|"请求3(串行)"| S1
    end

HTTP/1.1 的局限性:

问题 表现 影响
队头阻塞(HOLB) 一个请求阻塞后续所有请求 页面加载缓慢
无优先级调度 关键资源可能被排在后面 影响首屏渲染
头部冗余 每次请求都带完整头部 带宽浪费
无法服务器推送 只能客户端请求后才响应 增加 RTT

优化手段(治标不治本):
– 域名分片(Domain Sharding):用多个域名突破并发连接限制
– 雪碧图(CSS Sprites):合并小图为一张大图
– 资源内联:将 CSS/JS 直接内联到 HTML

3.2 HTTP/2 —— 多路复用

HTTP/2 基于 Google SPDY 协议,引入二进制分帧层(Binary Framing):

graph TB
    subgraph HTTP/2[单个 TCP 连接]
        Stream1["Stream 1 (资源A)"]
        Stream2["Stream 2 (资源B)"]
        Stream3["Stream 3 (资源C)"]
    end
    subgraph [二进制帧 - 交错传输]
        F1["Frame(Stream1, type=HEADERS)"]
        F2["Frame(Stream2, type=DATA)"]
        F3["Frame(Stream3, type=HEADERS)"]
        F4["Frame(Stream1, type=DATA)"]
        F5["Frame(Stream2, type=DATA)"]
    end
    Stream1 --> F1
    Stream1 --> F4
    Stream2 --> F2
    Stream2 --> F5
    Stream3 --> F3

HTTP/2 核心特性:

  • 多路复用:一个 TCP 连接内并行处理多个 Stream,解决 HTTP/1.1 队头阻塞
  • 头部压缩(HPACK):静态字典 + 动态字典(Huffman 编码),压缩率可达 80%
  • 服务器推送(Server Push):服务端可主动推送 CSS/JS 等资源,无需客户端请求
  • 流优先级:客户端可声明资源加载优先级

HTTP/2 的缺陷: 队头阻塞从 HTTP 层转移到了 TCP 层——TCP 丢包会导致所有 Stream 暂停,直到丢失的数据包被重传。

3.3 HTTP/3 —— 基于 QUIC

HTTP/3 将传输层从 TCP 替换为 QUIC(基于 UDP):

graph LR
    subgraph HTTP/3[HTTP/3 协议栈]
        H3[HTTP/3]
        QPACK[QPACK 头部压缩]
        QUIC[QUIC 传输层
基于 UDP
] TLS1_3[TLS 1.3
内置于 QUIC
] end subgraph HTTP/2[HTTP/2 协议栈] H2[HTTP/2] HPACK[HPACK 头部压缩] TLS[TLS] TCP[TCP] end subgraph HTTP/1.1[HTTP/1.1 协议栈] H11[HTTP/1.1] TLS_1[TLS] TCP_1[TCP] end

QUIC 解决了 TCP 的固有问题:

问题 TCP 方案 QUIC 方案
连接建立延迟 1~3 RTT(TCP 握手 + TLS 握手) 0-RTT(首次 1-RTT,后续 0-RTT)
队头阻塞 1 个丢包阻塞全部 Stream 每个 Stream 独立,丢包不影响其他
连接迁移 切换网络必须重建连接 用 Connection ID 标识,IP 变化不断连
头部阻塞 内核态的顺序化 用户态调度,无阻塞

HTTP/3 的 0-RTT 建立: 首次连接 1-RTT(QUIC 握手 + TLS 1.3 密钥协商),以后连接只需携带上次缓存的连接参数,直接发送请求数据。


四、HTTPS TLS 握手过程

4.1 TLS 1.2 握手(传统的 2-RTT)

sequenceDiagram
    participant C as Client
    participant S as Server

    Note over C: ClientHello<br/> TLS 版本<br/> 密码套件列表<br/> random_C
    C->>S: ClientHello
    Note over S: ServerHello<br/> 选定的TLS版本<br/> 选定的密码套件<br/> random_S<br/> 证书链<br/> ServerKeyExchange<br/> CertificateRequest
    S->>C: ServerHello + Certificate + ServerHelloDone
    Note over C: 验证证书<br/>生成 pre-master secret
    C->>S: ClientKeyExchange (pre-master)
    Note over C,S: 双方计算 master secret
    C->>S: ChangeCipherSpec + Finished
    S->>C: ChangeCipherSpec + Finished
    Note over C,S:  加密通道建立 (2-RTT)

4.2 TLS 1.3 握手(1-RTT / 0-RTT)

TLS 1.3 大幅简化握手流程,移除不安全的密码套件(RSA 密钥交换、RC4、3DES 等),仅支持 5 个安全套件:

sequenceDiagram
    participant C as Client
    participant S as Server

    Note over C:  推测服务器可能支持的 curves<br/> 直接发送 key_share
    C->>S: ClientHello<br/>+ supported_versions<br/>+ key_share (EC公钥)
    Note over S:  用客户端的 key_share 计算共享密钥<br/> 发送自己的 key_share<br/> 握手过程与加密数据合并
    S->>C: ServerHello + key_share + EncryptedExtensions + Certificate + Finished
    Note over C,S:  1-RTT 完成
    Note over C,S: 后续请求直接加密传输
    C->>S: HTTP 请求(加密)
    S->>C: HTTP 响应(加密)

    Note over C,S: 再连接 (0-RTT)
    C->>S: ClientHello + key_share + 0-RTT 数据
    Note over S:  PSK 恢复会话

TLS 1.3 的主要改进:

  1. 降为 1-RTT——握手阶段合并为一次往返
  2. 0-RTT 恢复——使用预共享密钥(PSK),首次请求即可携带数据(但需要防重放攻击)
  3. 移除不安全套件——仅支持 AEAD 加密算法(AES-GCM、ChaCha20-Poly1305)
  4. 简化协商——不支持自定义 TLS 扩展协商,减少攻击面

4.3 HTTPS 部署检查

# 使用 openssl 检查服务器 TLS 配置
openssl s_client -connect blog.jydeep.cn:443 -tls1_3

# 查看支持的密码套件
openssl s_client -connect blog.jydeep.cn:443 -cipher 'ECDHE+AESGCM'

# 使用 nmap 扫描 SSL 配置
nmap --script ssl-enum-ciphers -p 443 blog.jydeep.cn

现代 HTTPS 安全配置:

server {
    listen 443 ssl http2;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers on;

    # 会话缓存
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # HSTS(HTTP Strict Transport Security)
    add_header Strict-Transport-Security "max-age=63072000" always;
}

五、Wireshark 抓包实战分析

5.1 抓取三次握手

# 抓取特定端口的三次握手
tcpdump -i eth0 -n -c 3 'tcp port 443' -w tcp_handshake.pcap

# 用 Wireshark 命令行分析
tshark -r tcp_handshake.pcap -Y "tcp.flags.syn==1" -T fields \
  -e frame.number -e ip.src -e ip.dst -e tcp.seq -e tcp.ack -e tcp.flags

5.2 分析 HTTP/2 多路复用

通过 Wireshark 抓包可以看到 HTTP/2 的 Magic 帧和 SETTINGS 帧协商过程,Stream ID 奇偶区分客户端和服务端发起的流。

5.3 排查 TCP 重传和 ZeroWindow

# 查看 TCP 重传
tshark -r capture.pcap -Y "tcp.analysis.retransmission"

# 查看 Zero Window(接收端缓冲区满)
tshark -r capture.pcap -Y "tcp.window_size == 0"

六、总结

TCP/IP 和 HTTP 协议栈经过 40 多年的演进,已经从简单的可靠传输协议发展为涵盖安全、多路复用、低延迟的复杂体系:

  1. TCP 连接管理——三次握手同步序列号并协商参数,四次挥手保证优雅关闭,2MSL 的 TIME-WAIT 确保旧数据包不会干扰新连接
  2. 流量与拥塞控制——滑动窗口解决接收端处理速度不匹配,慢启动/拥塞避免/快速重传/快速恢复四阶段算法保障网络公平性
  3. HTTP 演进——HTTP/1.1 的队头阻塞被 HTTP/2 的多路复用解决,但 TCP 层面的队头阻塞又由 HTTP/3 的 QUIC 彻底消除
  4. HTTPS 安全——TLS 1.3 将握手从 2-RTT 优化到 1-RTT(甚至 0-RTT),移除不安全套件,是现代 HTTPS 的基石

理解这些协议原理后,无论是排查网络延迟、优化页面加载速度,还是配置 HTTPS 安全策略,都能从协议层面做出更准确的判断。

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容