跳转到内容

🤝 TCP 传输控制协议:面向连接的可靠传输

🌱 创建: 2026/04/01 ⏱️ 更新: 2026/05/22

TCP(Transmission Control Protocol,传输控制协议) 位于 OSI 模型的第四层(传输层),其初始核心规范定义于 1981 年的 RFC 793(现代综合规范见 RFC 9293)。

在网络层(IP 协议)仅提供“尽力而为(Best-Effort)”、无序且不可靠的数据包投递的基础上,TCP 通过极度复杂的握手、确认和重传机制,在两个通信节点之间建立起了一条面向连接的、可靠的、基于字节流的端到端逻辑通道。


IP 地址解决了“如何找到目标主机”的问题,而传输层的 TCP 和 UDP 引入了**端口(Port)**的概念,解决了“如何找到目标主机上的具体应用程序”的问题。

TCP 端口号是一个 16 位的无符号整数,范围从 $0$ 到 $65535$($2^16-1$):

  • 熟知端口(System Ports,0-1023):分配给核心网络服务(如 HTTP/80, HTTPS/443, SSH/22)。
  • 注册端口(User Ports,1024-49151):分配给特定的应用程序和服务(如 MySQL/3306, Redis/6379)。
  • 动态/私有端口(Dynamic Ports,49152-65535):客户端发起请求时由操作系统随机分配的临时源端口。

TCP 套接字(Socket)[源 IP:源端口][目的 IP:目的端口] 组成一个唯一的四元组。只要四元组不同,同一台服务器的同一个 80 端口就可以同时支撑数以万计的独立 TCP 连接。


2. 核心架构:TCP 报文头与控制标志位

Section titled “2. 核心架构:TCP 报文头与控制标志位”

TCP 在向 IP 层递交数据前,会为应用层的数据块附加一个极其复杂的报文头(TCP Header),标准长度为 20 字节(若带选项则更长)。

要理解 TCP 的行为,必须掌握报文头中的 6 个核心控制标志位(Control Flags),它们是驱动 TCP 状态机流转的指令:

admin@tech-fortress:~# tcpdump -n tcp[tcpflags]
标志位 (Flag)全称核心动作与语义说明
SYNSynchronize同步序列号。仅在建立连接的握手阶段使用,表示发起一个新的连接请求。
ACKAcknowledgment确认号有效。除了最初的第一个 SYN 包之外,TCP 通信中的所有数据包都必须将此标志位置为 1。
FINFinish结束发送。表示发送方的数据已经全部传输完毕,请求优雅地关闭连接。
RSTReset强制重置连接。通常由于接收到一个不属于当前任何活动连接的数据包(如端口未监听),协议栈会直接返回 RST 强行阻断异常连接。
PSHPush推送数据。通知接收方的 TCP 协议栈,不要将数据留在缓冲区中等待聚合,应立刻将其提交给应用层进程。
URGUrgent紧急指针有效。标记数据包中包含需要优先处理的紧急数据(现代网络开发中极少使用)。


3. 连接生命周期:三次握手与四次挥手

Section titled “3. 连接生命周期:三次握手与四次挥手”

TCP 是面向连接的,在发送任何有效载荷之前,必须在客户端和服务器之间建立严格的状态同步。这种机制被称为连接的建立与拆除。

3.1 建立连接:三次握手 (Three-Way Handshake)

Section titled “3.1 建立连接:三次握手 (Three-Way Handshake)”

三次握手的核心目的是在不可靠的网络上,双方确认彼此的发送与接收能力,并同步初始序列号(ISN)。

  1. 第一次握手 (SYN):客户端主动向服务器发送连接请求包,标志位 SYN=1,并随机生成一个初始序列号 Seq=x。此时客户端进入 SYN_SENT 状态。
  2. 第二次握手 (SYN-ACK):服务器收到请求,同意连接。服务器回复一个数据包,标志位 SYN=1, ACK=1,确认号 Ack=x+1,同时附带自己的随机初始序列号 Seq=y。此时服务器进入 SYN_RCVD 状态。
  3. 第三次握手 (ACK):客户端收到服务器的确认,向服务器发送最后的确认包。标志位 ACK=1,确认号 Ack=y+1,序列号 Seq=x+1。此时客户端进入 ESTABLISHED 状态。服务器收到此包后,也进入 ESTABLISHED 状态。连接正式建立。

工程逻辑:为什么需要三次?如果只有两次,服务器在发出 SYN-ACK 后就认为连接建立,但如果这个应答包在网络中丢失,客户端并未准备好,服务器就会白白分配内存资源挂起等待(这就是著名的 SYN Flood 攻击原理)。

3.2 拆除连接:四次挥手 (Four-Way Wavehand)

Section titled “3.2 拆除连接:四次挥手 (Four-Way Wavehand)”

由于 TCP 是全双工通信(Full-Duplex),即双方可以同时向对方发送数据。因此,每个方向的连接必须被独立关闭。

  1. 第一次挥手 (FIN):客户端数据发送完毕,主动发送 FIN 报文,进入 FIN_WAIT_1 状态。
  2. 第二次挥手 (ACK):服务器收到 FIN,回复 ACK,进入 CLOSE_WAIT 状态。此时客户端到服务器的方向已关闭(客户端不再发送业务数据),但服务器如果还有剩余数据,仍可继续向客户端发送。
  3. 第三次挥手 (FIN):服务器的数据也全部发送完毕,向客户端发送 FIN 报文,进入 LAST_ACK 状态。
  4. 第四次挥手 (ACK):客户端收到服务器的 FIN,回复最后的 ACK
    • 关键机制:TIME_WAIT。客户端发送完最终的 ACK 后,并不会立刻释放端口,而是进入 TIME_WAIT 状态,强制等待 2MSL(最大报文段生存时间,通常为 60 秒)。这是为了确保最后的 ACK 能够成功送达服务器,如果丢失,服务器会重传 FIN,客户端还能在 TIME_WAIT 窗口内补发 ACK

4. 可靠性的基石:序号与重传机制

Section titled “4. 可靠性的基石:序号与重传机制”

TCP 能够在一片混乱的 IP 路由网络中提供 100% 可靠的传输,依赖于其严密的跟踪与补偿机制:

4.1 序列号 (Sequence Number) 与确认机制 (ACK)

Section titled “4.1 序列号 (Sequence Number) 与确认机制 (ACK)”

TCP 将要发送的数据流分割成多个报文段(Segment)。它为每个字节都分配了一个连续的序列号。 接收方收到数据后,必须向发送方返回一个带有确认号(Acknowledgment Number)ACK 包,告诉发送方:“序列号 N 之前的所有数据我都收到了,我现在期待收到序列号 N+1 的数据。”

4.2 超时重传 (Retransmission Timeout, RTO)

Section titled “4.2 超时重传 (Retransmission Timeout, RTO)”

发送方在发出一部分数据后,会启动一个定时器。如果在规定的超时时间(RTO,通常根据往返时间 RTT 动态计算)内没有收到接收方的 ACK 确认,发送方会认为该数据包已在网络中丢失,并强制重新发送该报文段。

4.3 滑动窗口 (Sliding Window) 与流量控制

Section titled “4.3 滑动窗口 (Sliding Window) 与流量控制”

如果发送方发得太快,接收方的缓冲区(Buffer)会被塞满并开始丢包。 TCP 报文头中包含一个 窗口大小(Window Size) 字段。接收方在返回 ACK 时,会通过这个字段动态地告诉发送方自己目前还有多少剩余的缓冲区容量。发送方会严格根据这个窗口大小来控制发送速率,实现了完美的端到端流量控制(Flow Control)


在排查高并发服务器的性能瓶颈时,通过终端命令观察套接字状态是网络工程师的核心技能。

admin@tech-fortress:~# ss -atn | awk '{print $1}' | sort | uniq -c
连接状态 (State)含义与排错指引
LISTEN服务端正在监听特定端口,等待客户端发起 SYN 请求。
ESTABLISHED三次握手已完成,连接正常建立,双方正在传输应用层数据。
TIME_WAIT主动关闭连接的一方产生的最终驻留状态(等待 2MSL)。若服务器上出现海量 TIME_WAIT,通常是因为使用了短连接架构而未启用端口复用机制。
CLOSE_WAIT被动接收 FIN 的一方产生的状态。如果服务器出现大量 CLOSE_WAIT,属于严重异常,通常是业务代码出现了 Bug,没有正确调用 socket.close() 来释放连接。
SYN_RECV服务器收到了 SYN,已回复 SYN-ACK,正在等待客户端最后的 ACK。大量积压可能意味着遭受了网络层攻击。

  • RFC 793: Transmission Control Protocol (1981 年最初的基础规范)
  • RFC 9293: Transmission Control Protocol (TCP) (2022 年发布的最新 TCP 综合核心标准)
  • RFC 5681: TCP Congestion Control (TCP 拥塞控制算法规范)

最近更新: