TCP

返回 计算机网络

TCP(Transmission Control Protocol)提供面向连接、可靠、有序、全双工的字节流服务。HTTP/1.1、HTTPS、SSH、MySQL 等默认跑在 TCP 上。

UDP 对比见下文;基于 UDP 的 QUIC/HTTP/3 见 3


与 UDP 对比(摘要)

特性TCPUDP
连接面向连接(三次握手)无连接
可靠性可靠、有序不可靠、可能丢包乱序
流量/拥塞控制
头部20~60 字节8 字节
典型场景Web、API、数据库、文件DNS、流媒体、游戏、QUIC

TCP 报文段格式

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
┌─────────────────────────────────────────────────────────────────┐
│          源端口(16bit)          │         目标端口(16bit)       │
├─────────────────────────────────────────────────────────────────┤
│                        序列号 Sequence Number(32bit)            │
├─────────────────────────────────────────────────────────────────┤
│                        确认号 Acknowledgment Number(32bit)      │
├─────────┬───┬───┬───┬───┬───┬───┬──────────────────────────────┤
│数据偏移  │保留│URG│ACK│PSH│RST│SYN│FIN│     窗口大小(16bit)      │
├─────────┴───┴───┴───┴───┴───┴───┴───┴──────────────────────────┤
│            校验和(16bit)         │         紧急指针(16bit)      │
├─────────────────────────────────────────────────────────────────┤
│                     选项(0~40 字节)+ 填充                       │
└─────────────────────────────────────────────────────────────────┘
字段 / 标志作用
Seq本报文段第一个字节的序号
Ack期望收到的下一字节(累计确认)
窗口接收方剩余缓冲区(流量控制)
SYN建立连接
FIN关闭本方向发送
RST异常复位(端口未监听、拒绝连接、半开检测失败等)
PSH尽快交给应用层(如交互式终端)
URG带紧急数据(少用)

常见选项:MSS(最大段大小)、Window Scale(窗口扩大)、SACK(选择性确认)、Timestamps(RTT 测量与 PAWS)。


三次握手

客户端                                服务端
  │──── SYN(seq=x)────────────────────►│  [SYN_SENT]
  │◄─── SYN+ACK(seq=y, ack=x+1)────────│  [SYN_RCVD]
  │──── ACK(seq=x+1, ack=y+1)──────────►│  [ESTABLISHED]
  • 客户端:CLOSED → SYN_SENT → ESTABLISHED
  • 服务端:LISTEN → SYN_RCVD → ESTABLISHED

为何三次: 确认双方收发能力;避免旧 SYN 被当成新连接(历史连接请求)。

SYN Flood: 大量 SYN 不回 ACK,占满半连接队列。防护:tcp_syncookies、限速、WAF。

监听队列:

队列说明
半连接(SYN 队列)SYN_RCVD,等待第三次 ACK
全连接(Accept 队列)已完成握手,等待 accept()

listen(backlog)backlog 与内核 somaxconntcp_max_syn_backlog 共同决定上限;高并发服务需一并调优。

TCP Fast Open(TFO): 在 SYN 中携带 Cookie 与少量数据,重复访问域名时可减少 1 RTT(需客户端、服务端、中间设备支持)。


四次挥手与半关闭

主动方 ──── FIN ────► 被动方     「我不再发送」
被动方 ──── ACK ────► 主动方
被动方 ──── FIN ────► 主动方     「我也不发了」
主动方 ──── ACK ────► 被动方
主动方 进入 TIME_WAIT(2MSL)后 CLOSED

TIME_WAIT 作用: 保证最后一个 ACK 可达;让旧连接报文在网络中消散。

TIME_WAIT 过多(短连接、压测):

ss -s
ss -tan | awk '{print $1}' | sort | uniq -c
 
# Linux 调优(示例,按环境评估)
net.ipv4.tcp_tw_reuse = 1      # 仅客户端复用 TIME_WAIT 端口
net.ipv4.tcp_fin_timeout = 30

半关闭: TCP 是全双工,一方 shutdown(SHUT_WR) 只关写方向,仍可读对端数据;应用需正确处理 CLOSE_WAIT 堆积(忘记 close())。


状态机(概要)

CLOSED → SYN_SENT / SYN_RCVD → ESTABLISHED
       → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
       → CLOSE_WAIT → LAST_ACK → CLOSED

可靠传输

确认、超时与快速重传

  • 累计确认: Ack=N 表示 N 之前字节全部收到
  • RTO: 根据 RTT 自适应;超时未确认则重传
  • 快速重传: 收到 3 个重复 ACK 立即重传对应段,不等超时
  • SACK: 告知非连续已收块,减少不必要的重传

滑动窗口(流量控制)

发送窗口 = min(拥塞窗口 cwnd, 接收窗口 rwnd)
  • rwnd=0: 发送方停发并周期性发 零窗口探测(1 字节)
  • Window Scaling: 高 BDP 链路将窗口扩展到远超 64KB

MSS 与路径 MTU

  • MSS: 单段数据最大长度,通常由 MTU 推导(以太网常见 1460 字节 payload)
  • PMTUD / PLPMTUD: 发现路径 MTU,避免 IP 分片(分片丢一片则整包作废,对 TCP 不利)

拥塞控制

根据网络状况调节 cwnd(拥塞窗口):

阶段行为
慢开始cwnd 指数增长直至 ssthresh
拥塞避免每个 RTT 线性 +1 MSS
快重传 / 快恢复3 重复 ACK → 重传并 cwnd 减半恢复
超时cwnd 置 1,重新慢开始

CUBIC: Linux 默认,高带宽长延迟友好。

BBR: 以带宽与 RTT 估计 BDP,减轻 bufferbloat,不主要依赖丢包信号。

sysctl net.ipv4.tcp_congestion_control
sysctl -w net.ipv4.tcp_congestion_control=bbr

延迟相关行为

Nagle 与 TCP_NODELAY

Nagle: 小包合并,前一个段被 ACK 前不发新小包 → 降低小包数量。

延迟 ACK(常等 ~40ms 再确认)叠加时,交互应用可能多出几十毫秒延迟。

int on = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));

适用: 游戏、SSH 交互、自定义 RPC;不适用盲目关闭: 大量极小写入且对带宽敏感的场景。

TCP Keepalive

内核级探测空闲连接(与 HTTP Connection: keep-alive、WebSocket ping 不是同一概念):

net.ipv4.tcp_keepalive_time   = 7200
net.ipv4.tcp_keepalive_intvl  = 75
net.ipv4.tcp_keepalive_probes = 9

编程与调优要点

选项 / 概念说明
SO_REUSEADDR重启后快速绑定同一端口
SO_REUSEPORT多进程/线程负载均衡同一端口(Linux)
TCP_USER_TIMEOUT控制未确认数据的最长等待
TCP_QUICKACK提示尽快 ACK(短时)
全连接队列满客户端可能收到 SYN+ACK 后 RST 或超时

详见 Socket


诊断

ss -tnap
ss -tan | awk '{print $1}' | sort | uniq -c
ss -s
ss -tlnp | grep :8080
 
tcpdump -i eth0 host 192.168.1.100 -w cap.pcap
tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0'
tshark -r cap.pcap -Y "tcp.analysis.retransmission"
现象常见原因
大量 SYN_RCVDSYN Flood 或半连接队列过小
TIME_WAIT 爆炸短连接过多
重传率高链路丢包、拥塞、无线干扰
CLOSE_WAIT 堆积应用未关闭 socket
单连接吞吐上不去窗口小、拥塞算法、RTT 大、未开 GRO/GSO

常见 TCP 端口

端口用途
22SSH
80HTTP
443HTTPS
3306MySQL
5432PostgreSQL
6379Redis

DNS 亦可用 TCP 53(大响应);见 DNS


相关