网络协议深度解析-03-运输层:可靠数据传输与拥塞控制

全文摘要

本文将带你深入理解运输层的核心机制,帮助你掌握TCP和UDP的工作原理及适用场景。你将学到TCP如何实现可靠数据传输、三次握手与四次挥手的细节、拥塞控制的算法演进、以及UDP在实时应用中的优势。通过阅读本文,你将理解网络应用如何选择运输层协议,以及TCP/IP协议栈如何在不可靠的网络之上提供可靠的服务。

全书总结

运输层是网络协议栈中负责端到端通信的关键层次,它在不可靠的网络层之上提供可靠传输服务。本文系统梳理了TCP协议的可靠数据传输机制、连接建立与释放的过程、流量控制与拥塞控制算法、UDP协议的特点及适用场景,以及TCP/IP协议栈的演进历程。适合后端开发者、网络工程师、以及对网络底层原理感兴趣的技术人员阅读。


一、运输层的作用:端到端通信

网络层(IP协议)负责把数据包从源主机送到目的主机,但这是不够的。一台主机上可能同时运行着多个网络程序——浏览器、邮件客户端、音乐下载器,每个程序都在收发数据。IP层不知道这些数据该交给哪个程序。

运输层的任务是提供进程到进程的通信服务,确保数据被送到正确的应用程序。

flowchart TB
    subgraph HostA[主机A]
        App1[浏览器<br>进程1]
        App2[邮件客户端<br>进程2]
        TransA[运输层<br>复用/分用]
        NetA[网络层<br>IP]
    end

    subgraph Internet[互联网]
        IP[IP路由]
    end

    subgraph HostB[主机B]
        NetB[网络层<br>IP]
        TransB[运输层<br>复用/分用]
        App3[Web服务器<br>进程3]
        App4[邮件服务器<br>进程4]
    end

    App1 --> TransA
    App2 --> TransA
    TransA --> NetA
    NetA --> IP
    IP --> NetB
    NetB --> TransB
    TransB --> App3
    TransB --> App4

    style App1 fill:#e3f2fd
    style App2 fill:#e3f2fd
    style App3 fill:#c8e6c9
    style App4 fill:#c8e6c9

图表讲解:这张图展示了运输层在网络协议栈中的位置——它连接应用进程和网络层。

运输层的核心功能是复用(Multiplexing)和分用(Demultiplexing):

  • 复用:发送方,多个应用层进程的数据被运输层封装,共同使用一个网络层连接
  • 分用:接收方,运输层根据端口号将数据交付给正确的应用进程

这个机制通过端口号实现。端口号是16位整数,范围0-65535:

  • 0-1023:知名端口(Well-known Ports),由IANA分配,如HTTP(80)、HTTPS(443)、SSH(22)
  • 1024-49151:注册端口,由应用注册使用
  • 49152-65535:动态端口,客户端临时使用

例如,你同时用浏览器访问两个网站,浏览器会为每个连接分配本地端口(如54321、54322),但都使用目的端口80(HTTP)。服务器收到数据后,运输层根据源IP+源端口+目的IP+目的端口这个”四元组”来区分不同的连接,把数据交给对应的处理逻辑。


二、UDP:简单但不可靠

UDP(User Datagram Protocol,用户数据报协议)是运输层最简单的协议,它只做了最低限度的工作。

UDP的特点

flowchart LR
    App[应用层数据] --> UDP[添加UDP头部]
    UDP --> IP[IP层传输]

    UDP -->|包含| Field1[源端口]
    UDP -->|包含| Field2[目的端口]
    UDP -->|包含| Field3[长度]
    UDP -->|包含| Field4[校验和]

    style UDP fill:#fff9c4
    style IP fill:#e3f2fd

图表讲解:这张图展示了UDP头部的基本结构——简单到只有4个字段。

UDP头部只有4个字段,每个2字节:

  • 源端口:发送方端口号(可选,设为0表示不使用)
  • 目的端口:接收方端口号(必须)
  • 长度:UDP数据报的长度(包括头部)
  • 校验和:检测数据是否出错(可选)

UDP的特点:

  • 无连接:发送数据前不需要建立连接
  • 不可靠:不保证数据送达,不重传丢失的数据包
  • 无序:不保证数据包的顺序
  • 轻量:头部开销小(8字节),处理速度快

UDP的这些”缺点”在某些场景下反而是优势:

  • 实时应用:视频会议、在线游戏对延迟敏感,重传过时的数据包没有意义
  • 广播/多播:UDP支持一对多通信,适合视频直播、IPTV等场景
  • 简单服务:DNS查询(请求和响应都很小,丢包了再查询一次即可)、SNMP网络管理
  • 高性能:在可靠网络中,UDP的开销更小

三、TCP:可靠的运输层协议

TCP(Transmission Control Protocol,传输控制协议)提供了可靠、面向连接的字节流服务。它是互联网最复杂、最重要的协议之一。

TCP的可靠数据传输

网络层是不可靠的——数据包可能丢失、重复、乱序。TCP在不可靠的IP层之上构建了可靠的数据传输服务,使用了以下机制:

flowchart TB
    Sender[发送方] --> Seq[给数据编号<br>序列号]
    Seq --> ACK[等待确认<br>ACK]
    ACK --> Check{收到ACK?}
    Check -->|超时未收到| Retrans[重传数据]
    Check -->|正确收到| Next[发送下一个]

    Retrans --> ACK

    Retrans --> RTO[重传超时时间<br>动态调整]

    style Sender fill:#e3f2fd
    style Retrans fill:#ffcdd2
    style Next fill:#c8e6c9

图表讲解:这张图展示了TCP可靠传输的核心机制——通过序号、确认和重传来保证数据可靠送达。

序号(Sequence Number)是TCP可靠传输的基础。TCP把数据看作字节流,每个字节都有编号。发送方在头部包含数据的起始序号,接收方返回确认号(ACK),表示”期望收到的下一个字节序号”。例如,收到序号1000-1999的数据,返回ACK=2000。

重传是应对丢包的手段。发送方设置重传定时器,如果超时还没收到ACK,就重传数据。超时时间(RTO,Retransmission TimeOut)需要仔细设置——太短会不必要的重传,太长会影响响应速度。现代TCP根据测量的往返时间(RTT)动态调整RTO。

冗余ACK(Duplicate ACK)是更快速的丢包检测。如果接收方收到序号2000的数据,但还没收到1000,它会重复发送ACK=1000。发送方收到3个冗余ACK后,就知道中间有包丢失,立即重传,而不用等超时。这称为快速重传

流量控制让发送方不要发送太快,以免淹没接收方。接收方在TCP头部通告其接收缓冲区大小(窗口大小),发送方保证未确认的数据不超过这个窗口。

TCP连接建立:三次握手

sequenceDiagram
    participant C as 客户端
    participant S as 服务器

    C->>S: SYN<br/>序号=x
    S-->>C: SYN+ACK<br/>序号=y, 确认号=x+1
    C->>S: ACK<br/>确认号=y+1

    Note over C,S: 连接建立完成
    Note over C,S: 双方都知道对方的初始序号

图表讲解:这张时序图展示了TCP连接建立的三次握手过程——这是网络面试最常考的问题之一。

TCP是面向连接的协议,数据传输前需要先建立连接。三次握手的过程:

第一次握手:客户端发送SYN包(SYN=1),并选择一个初始序号x。客户端进入SYN_SENT状态。

第二次握手:服务器收到SYN包,返回SYN+ACK包(SYN=1,ACK=1)。ACK确认号是x+1,表示收到了客户端的SYN。服务器也选择自己的初始序号y。服务器进入SYN_RCVD状态。

第三次握手:客户端收到SYN+ACK包,发送ACK包(ACK=1),确认号是y+1,表示收到了服务器的SYN。客户端进入ESTABLISHED状态。服务器收到这个ACK后也进入ESTABLISHED状态。

为什么需要三次握手?两次不够吗?

  • 两次握手只能确认”客户端到服务器”的通道正常,无法确认”服务器到客户端”的通道
  • 如果只有两次握手,客户端发送的第一个SYN包在网络中滞留,后来才到达服务器,服务器会误以为是新的连接请求,建立连接并等待数据,浪费资源
  • 三次握手让双方都知道自己和对方的发送、接收能力都正常

TCP连接释放:四次挥手

sequenceDiagram
    participant C as 客户端
    participant S as 服务器

    C->>S: FIN<br/>序号=u
    S-->>C: ACK<br/>确认号=u+1

    Note over S: 服务器可能还有数据要发送

    S->>C: FIN<br/>序号=w
    C-->>S: ACK<br/>确认号=w+1

    Note over C,S: 连接关闭

图表讲解:这张时序图展示了TCP连接释放的四次挥手过程——比三次握手更复杂,因为TCP是全双工的。

TCP连接是全双工的,双方可以同时发送数据。关闭连接时,双方各自关闭自己的发送方向:

第一次挥手:客户端发送FIN包(FIN=1),表示没有数据要发送了。客户端进入FIN_WAIT_1状态。

第二次挥手:服务器收到FIN包,返回ACK包,确认号是u+1。此时服务器可能还有数据要发送给客户端。客户端进入FIN_WAIT_2状态。

第三次挥手:服务器发送完所有数据后,发送FIN包,表示自己也没有数据要发送了。服务器进入LAST_ACK状态。

第四次挥手:客户端收到FIN包,返回ACK包。客户端进入TIME_WAIT状态,等待2MSL(Maximum Segment Lifetime,报文最大生存时间)后完全关闭。服务器收到ACK后关闭。

TIME_WAIT状态的目的是:

  • 确保最后的ACK能到达服务器(如果丢了,服务器会重传FIN)
  • 等待网络中所有旧的包消失,避免影响新连接

四、TCP拥塞控制

流量控制是关于”接收方处理不过来”,拥塞控制是关于”网络拥堵”。TCP的拥塞控制是网络能够稳定运行的关键。

拥塞控制的四个算法

flowchart TB
    Start[开始发送] --> Slow[慢启动<br>指数增长]
    Slow --> Threshold{达到阈值?}
    Threshold -->|是| Avoid[拥塞避免<br>线性增长]
    Threshold -->|否| Slow

    Avoid --> Loss{检测到丢包?}
    Loss -->|超时| Reset[阈值减半<br>重新慢启动]
    Loss -->|3个冗余ACK| Fast[快速恢复<br>阈值减半<br>从新阈值继续]

    Reset --> Slow
    Fast --> Avoid

    style Slow fill:#fff9c4
    style Avoid fill:#e1f5fe
    style Fast fill:#c8e6c9
    style Reset fill:#ffcdd2

图表讲解:这张图展示了TCP拥塞控制的状态转换——这是互联网稳定运行的秘诀。

TCP拥塞控制包含四个核心算法:

慢启动(Slow Start):连接刚建立时,网络状况未知,从小的拥塞窗口(cwnd)开始,每个RTT(往返时间)翻倍。虽然叫”慢”,但实际增长很快(1→2→4→8→16…),只是为了避免突然发送大量数据导致拥塞。

拥塞避免(Congestion Avoidance):当cwnd达到慢启动阈值(ssthresh)后,进入拥塞避免阶段,cwnd每个RTT增加1,从指数增长变为线性增长,更谨慎地探测网络容量。

快速重传(Fast Retransmit):收到3个冗余ACK时,认为中间有包丢失,立即重传,不用等超时。

快速恢复(Fast Recovery):快速重传后,不进入慢启动,而是将cwnd减半,继续从拥塞避免阶段开始。这是因为收到冗余ACK说明网络还能传送数据,不是严重拥塞。

如果发生超时(说明严重拥塞),则将ssthresh设为当前cwnd的一半,cwnd重置为1,重新进入慢启动。


五、TCP的演进:从TCP Tahoe到TCP BBR

TCP拥塞控制算法经历了多次演进:

flowchart LR
    subgraph Tahoe[TCP Tahoe 1988]
        T1[超时:慢启动]
    end

    subgraph Reno[TCP Reno 1990]
        R1[增加快速恢复]
    end

    subgraph Cubic[TCP Cubic 2006]
        C1[立方函数增长<br>适合高带宽]
    end

    subgraph BBR[TCP BBR 2016]
        B1[基于带宽和RTT<br>不依赖丢包]
    end

    Tahoe --> Reno
    Reno --> Cubic
    Cubic --> BBR

    style Tahoe fill:#ffcdd2
    style Reno fill:#fff9c4
    style Cubic fill:#e1f5fe
    style BBR fill:#c8e6c9

图表讲解:这张图展示了TCP拥塞控制算法的演进——反映了网络环境的变化。

TCP Tahoe是最早版本,只有慢启动、拥塞避免、快速重传。超时后进入慢启动。

TCP Reno增加了快速恢复,3个冗余ACK后不进入慢启动,提高效率。但Reno在高带宽延迟网络(BDP)中表现不佳。

TCP Cubic在Linux中广泛使用,用立方函数调整cwnd,在高带宽网络中表现更好,是目前的默认算法。

TCP BBR是Google提出的新算法,它不把丢包作为拥塞信号(现代网络中丢包不一定意味着拥塞),而是实时测量带宽和RTT,以此调整发送速率。BBR在无线网络和跨洲传输中表现优异,正在逐渐普及。


结语

运输层是应用和网络之间的桥梁,它屏蔽了底层网络的复杂性,为应用提供简单、可靠的通信服务。

TCP的可靠传输、流量控制、拥塞控制是工程设计的典范——在不完美的基础设施上构建了可靠的通信系统。UDP的简单轻量,则在实时应用中找到了用武之地。

理解运输层的工作原理,能帮助你:

  • 选择合适的协议:需要可靠性的应用用TCP,对延迟敏感的应用用UDP
  • 优化性能:调整TCP缓冲区、启用TCP Fast Open等
  • 排查问题:连接超时、丢包、延迟高都与运输层相关

接下来的文章将深入网络层,看看IP协议如何实现跨网络的寻址和路由。


常见问题解答

Q1:为什么TCP需要三次握手,UDP不需要?

:TCP是面向连接的可靠协议,需要先建立连接确保双方都准备好通信。

三次握手让双方确认自己和对方的发送、接收能力都正常,并协商初始序号。

UDP是无连接的,每个数据包独立发送,不需要建立连接。就像打电话需要对方接听后才能说话(TCP),而发短信直接发出去就行,不管对方是否收到(UDP)。

连接的代价是建立连接的开销(三次握手至少一个RTT),好处是可靠性、流量控制、拥塞控制。UDP没有这些开销,但也失去了这些保障。


Q2:TIME_WAIT状态有什么危害?如何处理?

:TIME_WAIT状态的连接会占用端口和内存资源。

在高并发服务器上,如果大量连接进入TIME_WAIT状态,可能耗尽可用端口(临时端口范围有限),导致无法建立新连接。

处理方法:

(1)调整net.ipv4.ip_local_port_range增加临时端口范围。

(2)启用net.ipv4.tcp_tw_reuse允许重用TIME_WAIT状态的端口。

(3)优化应用逻辑,让客户端而不是服务器先关闭连接(因为主动关闭方才会进入TIME_WAIT)。

(4)使用连接池复用连接,减少频繁的建立和关闭。

TIME_WAIT状态是TCP协议正常工作所必需的,不能完全消除,只能优化管理。


Q3:什么是SYN Flood攻击,如何防御?

:SYN Flood是一种DDoS攻击。

攻击者发送大量SYN包但不完成三次握手,服务器为每个SYN分配资源并等待,最终资源耗尽,无法为正常用户服务。

防御方法:

(1)SYN Cookies:服务器不立即分配资源,而是用一种编码的初始序号(包含连接信息),收到ACK时解码验证,如果合法才分配资源。

(2)增大SYN队列:net.ipv4.tcp_max_syn_backlog。

(3)启用SYN Proxy:防火墙代答SYN/ACK,完成三次握手后再与服务器建立连接。

(4)限流:限制单个IP的SYN频率。

现代操作系统和云服务都有内置的SYN Flood防护。


Q4:TCP Keep-Alive和HTTP Keep-Alive有什么区别?

:两者名字相似但完全不同。

TCP Keep-Alive是TCP层的机制,定期发送探测包,确认连接是否还活着。如果长时间没有数据传输,TCP可能不知道对方已经断开,Keep-Alive可以检测死连接。

HTTP Keep-Alive是HTTP层的机制,允许在一个TCP连接上发送多个HTTP请求,避免为每个请求建立新连接的开销。HTTP Keep-Alive也称为持久连接(Persistent Connection),是HTTP/1.1的默认行为。

TCP Keep-Alive默认关闭(因为会额外消耗带宽),HTTP Keep-Alive默认开启(因为性能提升明显)。


Q5:为什么QUIC使用UDP而不是TCP?

:QUIC使用UDP主要是为了突破TCP的局限。

TCP的问题是队头阻塞——当一个包丢失时,后续的包即使到达也无法交付,要等丢包重传后才能按序交付。这在高丢包率环境下严重影响性能。

QUIC在UDP之上实现了类似TCP的可靠性,但更灵活:

(1)多路复用:不同流(stream)独立,一个流的丢包不影响其他流。

(2)连接迁移:用Connection ID而不是四元组标识连接,换网络(WiFi切4G)不断线。

(3)更快的握手:0-RTT建立连接,TCP需要1-RTT。

(4)集成TLS:加密传输更安全。

QUIC是HTTP/3的基础,特别适合移动网络和不稳定网络环境。


更新时间:2026年3月2日 作者:网络技术专栏 标签:#TCP UDP 可靠传输 拥塞控制 三次握手