如何选择UDP与TCP

在如图 9.1 所示的 TCP/IP 四层结构中,网络传输层是最为重要的一层协议。该层中包含了两种协议:TCP 和 UDP,它们都是我们经常使用的网络协议。

其中,TCP 是可靠传输协议,它可以保证数据在传输过程中不丢失、不乱序(不抖动)。对于大部分网络应用程序而言,TCP 为传输数据提供了非常好的网络质量,满足了日常需求,这也就是 90% 以上的网络应用程序选择 TCP 的原因。

但 TCP 有个很大的缺点,即其可靠性是以牺牲实时性为代价的。按照 TCP 原理,当出现极端网络情况时,理论上每个包的时延可达到秒级以上,而且这种时延是不断叠加的。这对于音视频实时通信来说是不可接受的。

TCP 为什么会产生这么大的时延呢?这就要了解一下 TCP 的工作原理了。我们都知道,TCP 为了实现数据传输的可靠性,采用的是 “发送→确认→丢包→重传” 这样一套机制。而且为了增加网络的吞吐量,还采用了延迟确认和 Nagle 算法。这套机制就是 TCP 产生延迟的根本原因。下面通过延迟确认示意图(如图 9.2 所示)介绍一下 TCP 时延是如何产生的。

从图 9.2 中可以看到,为了增加网络的吞吐量,接收端不必每收到一个包就确认一次,而是对一段时间内收到的所有数据集体确认一次即可。为了实现该功能,TCP 通常会在接收端启动一个定时器。定时器的时间间隔一般设置为 200ms,即每隔 200ms 确认一次接收到的数据。这就是延迟确认机制。除此之外,TCP 在发送端也启动了一个定时器,不过该定时器的功能不是发送确认消息,而是用来判别是否有丢包的情况。发送端定时器的时长为一个 RTO。如果在定时器超时后仍然没有收到包的确认消息,则认为包丢失了,需要发送端重发丢失的包。这就是 TCP 的丢包重传机制。

image 2025 02 23 17 11 40 437
Figure 1. 图9.1 TCP/IP四层结构
image 2025 02 23 17 12 05 569
Figure 2. 图9.2 TCP延迟确认与丢包重传

了解了 TCP 的延迟确认和丢包重传机制后,我们假设一种场景:在图 9.2 中,假如接收端发送的确认消息❶丢失了,按 TCP 的协议规则,通信双方会怎么做呢?首先,发送端只有等到定时器超时后,才能发现该包丢失了。确认丢包后,发送端会将前面所有未确认的包重发一遍。如果在收到数据后,接收端发送的确认消息又丢失了,那么发送端还要等到定时器超时后才能知道包丢失了。因此,在遇到这种极端网络的情况下,TCP 传输的时延要累加很多,这种时延是不可控的。

既然 TCP 无法满足音视频实时性的要求,那么 UDP 是否可以呢?与 TCP 相反,UDP 属于不可靠传输协议。在传输数据时,它不保证数据能可靠到达,也不保证数据有序,但它最大的优点就是传输速度 “快”。由于 UDP 没有 TCP 那一套保证数据可靠、有序的控制逻辑,所以它不会被 “人为” 地变慢,因此它的实时性是最高的。但 UDP 如何解决丢包和抖动问题呢?如果为 UDP 增加解决丢包和抖动的机制,会不会又成了另一个 TCP 呢?

对于上述问题,WebRTC 给出了一套比较完美的解决方案,通过 NACK、FEC、Jitter Bufer 以及 NetEQ 技术既可以解决丢包和抖动问题,又不会产生影响服务质量的时延。通过上面的分析可以知道,由于 TCP 在极端网络情况下无法控制传输的时延大小,所以在做实时通信传输时,应该首选 UDP。