TCP(Transmission Control Protocol)是一种面向连接、可靠、有序的传输层协议,它把底层可能丢包、乱序、重复到达的网络传输,抽象成应用可以连续读写的双向字节流。
核心问题
IP 层只尽力把数据包送到目标 IP 地址,不保证到达、不保证顺序、不负责重传,也不知道应用消息边界。应用如果直接面对这种服务,就要自己处理丢包、乱序、重复包、流量过快和网络拥塞。
TCP 解决的是“如何在不可靠网络上给应用提供可靠、有序、可控速率的进程到进程通信”的问题。它不是让网络变可靠,而是在两端主机内核中维护状态、编号、确认、重传和窗口,把复杂性藏在协议实现里。
核心机制
TCP 连接通常由四元组标识:
(源 IP, 源端口, 目的 IP, 目的端口)其中 IP 地址 定位主机或网络接口,端口 定位主机上的传输层入口。一个 Web 服务器可以在同一个 IP:443 上同时服务很多客户端,因为每个客户端的源 IP 和源端口不同,四元组不同。
TCP 的核心对象包括:
| 对象 | 含义 |
|---|---|
| sequence number | 字节序号,标记本段数据在字节流中的位置 |
| acknowledgement number | 确认号,表示“我已经收到这个编号之前的字节” |
| receive window | 接收窗口,告诉对端自己还能接收多少数据 |
| retransmission timer | 重传定时器,用于检测可能丢失的数据段 |
| send/receive buffer | 内核中的发送缓冲区和接收缓冲区 |
建立连接的典型三次握手是:
客户端 -> 服务端:SYN, seq = x
服务端 -> 客户端:SYN + ACK, seq = y, ack = x + 1
客户端 -> 服务端:ACK, ack = y + 1三次握手不是“打招呼”这么简单,它至少完成三件事:确认双方收发路径可用、交换初始序列号、让双方内核进入一致的连接状态。
可靠传输的核心循环可以简化为:
发送方:给每段字节编号 -> 发送 -> 等 ACK
接收方:按序接收 -> 缓存乱序片段 -> 返回 ACK
发送方:超时或收到重复 ACK -> 重传可能丢失的数据TCP 还要同时做两类速率控制:
- 流量控制:接收方通过窗口告诉发送方“我还能吃下多少”,避免把对方内核缓冲区打爆。
- 拥塞控制:发送方根据丢包、延迟和 ACK 节奏估计网络拥塞,控制自己向网络灌入数据的速度。
工程用途
- Web 协议:HTTP/1.1、HTTP/2 和 WebSocket 常运行在 TCP 上。
- 数据库连接:客户端和数据库服务端通过 TCP 长连接交换请求和响应。
- 远程登录和文件传输:SSH、SFTP、很多 RPC 框架依赖 TCP 的可靠字节流。
- 应用层长连接:长连接 复用同一条 TCP 连接,减少握手成本并支持持续推送。
常见观察指标包括连接数、SYN backlog、accept 队列、重传率、RTT、拥塞窗口、接收窗口、TIME_WAIT 数量、连接建立耗时和 socket 读写阻塞时间。
边界与常见坑
- TCP 是字节流,不是消息协议:一次
send()不一定对应一次recv();应用必须用长度字段、分隔符或上层帧协议处理粘包/拆包。 - 可靠不等于永远不断:网络长时间中断、对端崩溃、NAT 超时、内核缓冲区耗尽都可能让连接失败。
- 有序会带来队头阻塞:前面某段丢失时,后面已到达的数据也不能直接交给应用层字节流。
- 连接是内核状态,不只是 fd:Socket 文件描述符只是应用访问连接状态的句柄。
- 关闭也有协议状态:FIN 表示正常半关闭,RST 表示异常重置,TIME_WAIT 用来吸收旧包并保证对端能收到最后 ACK。
- TCP 不定义业务语义:鉴权、请求响应、消息边界、重试幂等性仍由上层协议处理。