TCP和UDP的对比通常被简化为一句话:TCP可靠,UDP不可靠。
站在协议的角度,这句话挑不出毛病,可它把工程上最关键的那层盖住了——’可靠‘与’不可靠‘从来不是谁好谁坏,而是两种不同的取舍:TCP 押可靠性,账单是排队与等待;UDP 押自主权,换来的是即时性与对细节的掌控。落到加速这件事上,两者要走的是完全不同的两条路:优化 TCP 主要是在替它承担可靠性带来的延迟开销,优化 UDP 则是在’不保证送达‘的底子上,有选择地去补偿丢包。
两边的加速手段不能混用:把TCP那套逻辑搬到UDP上会伤实时性,把UDP那套搬到TCP上又解决不了窗口增长受限的问题。
TCP的代价:顺序交付与队头阻塞
TCP向应用层提供一个保证:数据按发送顺序到达,不丢、不重、不乱。为了维持这个保证,TCP在协议栈内部做了几件事。
接收的一端会维护一个用于重排的缓冲区。IP 网络里先后顺序被打乱是家常便饭,因为不同数据包未必走同一条路;一旦次序与发送时不吻合,接收端就必须先把缺口等着补齐,才敢把后面的数据交给应用。这便是队头阻塞(Head-of-Line Blocking):仅仅丢了一个包,后面所有已经抵达的包都得跟着一起被扣住。
链路的 RTT 越长,队头阻塞越难熬。举个具体的数:RTT 为 200ms 时丢了一个包,接收端至少要等 200ms 才拿得到重传;而这 200ms 里,所有陆续抵达的包都被压在缓冲区中。于是应用层感受到的并不是’过了 200ms 数据就回来了‘,而是’先沉默 200ms,接着数据一股脑涌进来‘。放在网页加载上,就是某个资源卡着不动然后突然完成;放到实时场景里则无法接受——200ms 之前的游戏状态,早就失去了意义。
TCP 的另一项代价来自拥塞控制的保守。慢启动阶段窗口指数级膨胀,看上去很激进,可一旦逼近链路容量,基于丢包的算法会主动制造丢包来试探上限,随后把窗口砍下来重新爬升。这个过程在短 RTT 链路上转瞬即逝;到了长 RTT 链路上,每丢一次包都要花好几个 RTT 才能重新跑回满速。
加速器如何介入TCP
TCP加速器的核心逻辑是:把TCP的代价隔离在短RTT段内。
加速器把一条端到端的 TCP 切成两段之后,每一段的 RTT 都会明显变短——用户到加速节点这一段,往往只有直连时的三分之一到四分之一。队头阻塞并不会消失,但它持续的时间与 RTT 成正比:RTT 越短,卡住的时间就越短。窗口的恢复过程同样被压缩:一个在 200ms RTT 上要花 2 秒才爬完的窗口恢复,换到 50ms RTT 上只需要 0.5 秒。
不过拆分成两段也有副作用:两条 TCP 各自为政,彼此的拥塞状态互不通气。用户到节点这一段可能带宽富余、窗口一路涨上去;节点到目标那一段却在排队、窗口被压着。于是数据从用户侧高速灌进节点,堵在它的发送缓冲区里。一旦堆积量超过’节点到目标‘这段链路的带宽延迟积,多出来的排队时间就在加速器内部凭空生成了。
这意味着,加速器的有效运作要求节点的缓冲区管理策略与两段链路的带宽差异匹配。如果入口链路远快于出口链路(比如用户是千兆宽带,出口链路因为跨洋而只有几十Mbps的有效吞吐量),节点必须主动向用户端施加反压——通过调整TCP窗口或延迟ACK来降低入口段的发送速率。不做这个优化的加速器,会在节点内部制造自己的拥塞点。
UDP的设计:不保证,不阻塞
UDP向应用层提供的是一个完全不同的契约:数据报尽力交付,不保证到达,不保证顺序。如果数据报丢失,UDP不重传。如果数据报乱序,UDP不重排。应用层收到什么就是什么,UDP不替应用做任何决定。
恰恰是这个’不替应用拿主意‘的设计,成了众多实时应用倒向 UDP 的理由。游戏、VoIP、实时视频这几类应用,要的是及时,其次才是完整。语音包丢了,宁可听一小段静音,也不愿意等 200ms 再把那份早已过时的音频插进当前进度;游戏里的位置更新丢了也没关系,只要更新频率够高,下一个包几毫秒之内就已经把它覆盖掉了。
UDP把可靠性决策权交给了应用层。应用可以自己实现选择性重传(只重传关键数据包),可以实现FEC(用冗余换丢包恢复),也可以什么都不做(容忍丢包)。这种灵活性是UDP在实时场景中的核心价值。
但UDP在公网上有一个结构性的劣势:网络中间设备对它的态度。
拥塞真正发生的时候,路由器的队列管理往往站在 TCP 这一边。像 WRED 这类主动队列管理算法会有选择地丢 UDP 包,理由很直接:UDP 不会像 TCP 那样收到拥塞信号就减慢发送。于是一条不肯减速的 UDP 流,在拥堵的链路上被打成’不合作的流量‘,优先被标记甚至丢弃。这也解释了为什么网络高峰期 UDP 的丢包率通常高于 TCP——问题不在 UDP 本身更脆弱,而在于设备策略天生倾向于维护 TCP 的公平。
加速器对UDP能做什么

UDP加速不需要拆分连接,因为UDP没有连接。UDP加速不需要管理拥塞窗口,因为UDP没有窗口。那么加速器在做什么?
路径选择仍然是第一位的。如果加速器能将UDP数据包从一条丢包率2%的公共路径迁移到一条丢包率0.2%的私有骨干网路径,加速效果直接体现在应用层的丢包减少上。这部分逻辑和TCP加速相同,但对UDP的收益往往更明显——因为UDP对丢包没有自愈能力,丢一个就是一个。
在这条更优的路径之上,加速器可以在两端节点之间增加FEC。发送端在连续N个数据包后附加M个冗余包,使得接收端在N+M个包中任意丢失不超过M个时都能完整恢复。FEC不消除丢包——物理链路上的数据包仍然在丢失——但它让应用层感知到的丢包率降到零。
FEC 不是免费的,账单主要是带宽开销与编码时延。发送端要攒够一定数量的数据包才能算出冗余包:对每秒 60 个更新包的游戏流量来说影响很小(攒够 4 个包大约只要 67ms),但低频流量可能得等上更久。这段等待再加上编码运算本身的耗时,合起来就是加速器自己引进来的一段处理延迟。
在工程实践中,经常观察到一个权衡:开启FEC后,游戏内显示的丢包率下降,但基础ping值增加了3-5ms。对大多数玩家来说,丢包率从1%降到0带来的体验改善远大于ping值增加5ms的代价。但对于对延迟极度敏感的场景(比如职业电竞),这个权衡需要被明确意识到。
误判:QUIC与”UDP加速”
QUIC是一个基于UDP的传输协议,它在应用层实现了类似TCP的可靠传输和拥塞控制。很多加速服务声称支持”UDP加速”,但实际测试会发现它们对QUIC的处理并不一致。
一些加速器将QUIC流量当作普通UDP处理——单纯转发,不做FEC,不做路径优化。这是合理的,因为QUIC已经内置了拥塞控制和丢包恢复,外部的FEC可能干扰QUIC自身的速率调节逻辑。但如果加速器对QUIC什么都不做,用户看到的效果就和直连没有区别(除了路径可能不同)。
另一些加速器会尝试对QUIC流量也做TCP式的分段中继——终结QUIC连接,在内部用自定义协议传输,到出口节点再重建QUIC连接。这种做法等于破坏了QUIC的端到端加密和认证模型,通常需要客户端安装根证书才能中间人解密。对用户来说,带来的安全风险可能超过加速收益。
一个更容易混淆的情况是,加速器宣称”UDP加速”,但实际只优化了特定端口的UDP流量(比如常见的游戏端口),而对QUIC使用的443端口的UDP流量走的是另一套逻辑(甚至可能被降级为直连)。用户在测速时看到UDP加速有效,但在使用QUIC的应用(比如基于HTTP/3的网站、某些视频流)时感受不到改善,原因就在这里——两种UDP流量经过了不同的处理管道。
# 检查某个应用使用的UDP端口和协议 # QUIC通常使用UDP 443 ss -tunlp | grep 应用进程名 # 抓包观察UDP流量的行为模式 # QUIC的包通常较大,且有TLS握手的特征 tcpdump -i eth0 -n udp port 443 -c 50
协议的边界与选择
回头看,TCP 与 UDP 在加速上的分歧,根源就在它们对应用层许下的承诺不同。TCP 承诺可靠且有序,所以加速器只能用分段的方式,把这些承诺附加的延迟成本隔离出去;UDP 什么都不承诺,加速器的手脚反而更受约束——既不能假定包的含义,也不能重排顺序,更不便随意加延迟,可做的无非是优化路径与少量冗余。
正是这个差异决定了应用与手段的配对关系。网页和 API 调用跑在 TCP 上,需要压的正是握手延迟与窗口爬升时间;游戏和实时通信依赖 UDP,重点则是压低丢包率与路径抖动。若把为 TCP 设计的方案硬套到 UDP 流量上,比如强行做分段中继,结局要么是 UDP 的实时性被破坏,要么干脆因为协议不适配而连不上。
反过来,如果试图用UDP的”尽力而为”逻辑去加速TCP——比如只做路径转发不做连接分段——那等于放弃了所有TCP层面的优化可能,退化为一个纯粹的VPN。
弄明白两个协议在设计时的取舍,目的不在于背下各自的清单,而是当你看到某个加速方案时,能判断它的核心逻辑是围着哪个协议转的,以及这套逻辑和你手里那份流量有多匹配。二者无法互换,偏偏多数用户并不清楚自己在跑哪个协议。相比直接比较各家给出的延迟数字,先把流量的协议构成摸清楚更有价值。