为什么视频直播平台实际上在用 TCP 而非 UDP?
为什么视频直播平台实际上在用 TCP 而非 UDP?
B站、抖音、YouTube Live 等大型直播平台,主要使用的是基于 TCP 的 HTTP 协议来分发直播流。而"视频直播用 UDP"这句话并不是错的,只是它描述的是另一类场景。要彻底搞清楚这件事,我们需要从几个层面来拆解。
一、先搞清楚:UDP 和 TCP 在传输视频时的核心区别是什么
TCP 的特点
TCP 是一种可靠传输协议。它有三个关键机制:
- 保证数据完整到达:每发一个数据包,接收方都要回复确认(ACK)。如果发送方没有收到确认,就会重新发送这个包。
- 保证数据顺序正确:即使网络中数据包到达的顺序是乱的,TCP 也会在接收端把它们按正确顺序重新排列好,再交给上层应用。
- 拥塞控制:TCP 会根据网络状况动态调整发送速度,网络拥堵时主动降速,避免雪崩。
这三个机制意味着什么?意味着数据一定是完整的、有序的,但代价是——如果某个包丢了,后面所有的包都要等着,直到丢的那个包被重传并补回来。这个现象叫做队头阻塞(Head-of-Line Blocking)。
对于视频传输来说,队头阻塞会带来额外的延迟。
UDP 的特点
UDP 是一种不可靠传输协议。它的设计哲学极其简单:
- 不保证数据到达:发出去就不管了,丢了就丢了。
- 不保证数据顺序:包到了就到了,先到的先处理。
- 没有拥塞控制:应用想发多快就发多快(当然网络本身可能会丢包)。
这意味着 UDP 几乎没有额外延迟,但数据可能不完整。
关键问题来了:视频传输到底能不能容忍丢包?
这取决于场景。这正是理解这个问题的核心所在。
二、两种完全不同的"直播"场景
人们笼统地说"直播用 UDP",是因为把两种截然不同的场景混在了一起。我们必须把它们分开。
场景一:实时互动通信
典型例子:
- 微信视频通话
- Zoom / 腾讯会议等视频会议
- 游戏中的语音聊天
- 连麦互动(主播和主播之间、主播和观众之间)
这类场景的核心需求是极低延迟,通常要求端到端延迟在 100~500 毫秒以内。为什么?因为这是双向交流。你说一句话,对方要立刻听到并回应。如果延迟超过 500 毫秒,对话就会变得非常别扭,互相抢话。
在这种场景下:
- 丢了几个包?没关系。画面花一下、声音卡一下,人类大脑可以脑补。
- 但是如果因为重传一个丢失的包,导致整个画面卡住 200 毫秒等待,那是不可接受的——对方说的话你过了半秒才听到,交流根本无法进行。
所以这类场景确实使用 UDP(或者基于 UDP 构建的协议,比如 RTP/RTCP、WebRTC 内部就跑在 UDP 上)。这里的逻辑是:宁可丢几帧画面,也绝不能有延迟。
场景二:大规模单向直播分发
典型例子:
- B站直播
- 抖音直播
- YouTube Live
- Twitch
- 电视台网络直播
这类场景的特征是什么?
- 单向的:一个主播,几千、几万、甚至几百万观众同时观看。观众不需要和主播进行毫秒级的实时互动。
- 延迟容忍度相对高:大多数观众可以接受 3~10 秒的延迟。你看 B 站直播时,弹幕里有人说"进球了!",你可能两三秒后才看到画面——这完全不影响你的观看体验。
- 画质要求高:观众希望看到清晰、流畅、不花屏、不卡顿的画面。丢包导致的花屏和音画不同步是不可接受的。
- 规模极大:一个热门直播间可能有几百万人同时观看。
在这种场景下,优先级完全反过来了:宁可多几秒延迟,也绝不能丢数据导致花屏卡顿。
这就是为什么大规模直播分发使用 TCP。
三、m3u8 + m4s 到底是什么?——HLS 协议详解
我们在 B 站直播后台,可以看到许多 m3u8 和 m4s,这是 HLS(HTTP Live Streaming) 协议的组成部分。这是苹果公司在 2009 年提出的一个直播/点播协议。我们来拆解它的工作原理。
基本思路:把直播流切成一段段小文件
HLS 的核心思想极其朴素:
- 主播端把连续的视频流实时编码。
- 服务器端把这个连续的视频流切成一小段一小段的文件,每段通常是 2~6 秒长。
- 服务器同时维护一个播放列表文件,告诉播放器:“目前最新的几个视频片段是什么,去哪里下载它们。”
- 观众端的播放器定期去请求这个播放列表,发现有新片段,就去下载、解码、播放。
m3u8 文件:播放列表
m3u8 本质上是一个文本文件,后缀名 .m3u8。它的内容类似这样(简化示意):
#EXTM3U
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:12001
#EXTINF:4.0,
segment_12001.m4s
#EXTINF:4.0,
segment_12002.m4s
#EXTINF:4.0,
segment_12003.m4s
这个文件在说什么?
- 每个片段大约 4 秒长。
- 当前最新的三个片段分别是 12001、12002、12003。
- 播放器应该去下载这三个文件来播放。
播放器每隔几秒就会重新请求一次这个 m3u8 文件,看看有没有新的片段出现。如果出现了 segment_12004.m4s,它就去下载这个新片段,接着播放。
这就是直播的实现方式——不断追踪最新的片段。
m4s 文件:视频片段本身
m4s 是 fMP4(Fragmented MP4) 格式的片段文件。每个 m4s 文件包含了几秒钟的视频和音频数据,编码格式通常是 H.264 或 H.265(视频)和 AAC(音频)。
播放器下载这些 m4s 文件后,解码播放,一个片段接着一个片段,观众就看到了连续的直播画面。
为什么这套方案全部跑在 HTTP/TCP 上?
注意看:播放器获取 m3u8 和 m4s 的方式,就是普通的 HTTP 请求——跟你在浏览器里下载一个网页、一张图片,本质上没有任何区别。
这意味着:
- m3u8 文件 → 一次 HTTP GET 请求
- 每个 m4s 文件 → 一次 HTTP GET 请求
HTTP 协议跑在 TCP 上。你看到的 h2 就是 HTTP/2,它是 HTTP 协议的第二个大版本,底层仍然是 TCP。
四、为什么大规模直播选择了基于 TCP 的 HLS/DASH,而不用 UDP?
这不是一个技术能力的限制,而是一个深思熟虑的工程权衡。原因有以下几个层面:
原因一:CDN 基础设施的兼容性
这是最重要的原因。
CDN(Content Delivery Network,内容分发网络) 是大规模直播分发的基石。当 B 站一个直播间有 100 万人同时观看时,不可能让这 100 万人都去连同一台服务器——那台服务器会被瞬间压垮。
CDN 的做法是:在全国(甚至全球)部署成千上万的边缘节点服务器。北京的用户从北京的节点拿数据,广州的用户从广州的节点拿数据。每个节点只需要从上游拿一份数据,然后分发给它附近的成千上万的用户。
而全球现有的 CDN 基础设施(Akamai、Cloudflare、阿里云 CDN、腾讯云 CDN 等),几乎全部是基于 HTTP/TCP 构建的。它们天然支持缓存 HTTP 响应——m3u8 是一个 HTTP 响应,m4s 也是一个 HTTP 响应,CDN 节点可以轻松地缓存这些响应,分发给大量用户。
如果要用 UDP 来做大规模分发,要另起一套完全不同的分发基础设施。这在工程上的成本是极其巨大的。
HLS/DASH 之所以被设计成基于 HTTP 的,正是为了直接复用整个互联网已有的 HTTP/CDN 基础设施。这是一个天才级别的工程决策。
原因二:防火墙和网络穿透
互联网上的大量防火墙、NAT 设备、企业网关,对 UDP 流量非常不友好。很多网络环境会直接封掉 UDP 端口,或者对 UDP 流量做严格的限速。
但是 HTTP/TCP 流量?几乎不会被封。因为整个互联网的网页浏览都跑在 HTTP 上,没有哪个网络管理员会封掉 HTTP。特别是 HTTPS(HTTP over TLS),走的是 443 端口,这是全世界最"通行无阻"的端口。
用基于 HTTP 的直播协议,意味着在任何能上网的地方,都能看直播。这对于面向大众的直播平台来说至关重要。
原因三:大规模分发场景下,TCP 的"缺点"并不致命
前面说了,TCP 的核心缺点是队头阻塞带来的额外延迟。但在 HLS 的架构下,这个缺点被大幅缓解了:
- HLS 本身就有 3~10 秒的固有延迟(因为要等一整个片段生成完毕才能开始下载)。在这个量级的延迟面前,TCP 重传一个丢失的包所增加的几十毫秒延迟,根本不值一提。
- 每个 m4s 片段就是一次独立的 HTTP 下载。下载完一个片段后,播放器有充足的时间缓冲,TCP 的重传机制不会造成播放卡顿。
换句话说,HLS 的架构天然就不追求极低延迟,所以 TCP 的延迟代价在这里几乎没有感知。
原因四:数据完整性对观看体验至关重要
直播虽然是"实时"的,但观众看到的本质上是一段段编码后的视频文件。视频编码(如 H.264/H.265)的特点是:
- 数据是高度压缩的。一个关键帧(I 帧)可能只占几十 KB,但它描述了整个画面。后续的帧(P 帧、B 帧)只记录与前一帧的差异。
- 如果丢失了一个关键帧的数据,后面几十帧甚至上百帧都无法正确解码,屏幕上会出现大面积花屏、马赛克、色块乱飞的现象。
- 如果丢失了音频数据,会出现爆音、断音。
在实时视频通话中,丢几个包还勉强能忍,因为对方就在跟你对话,你大脑可以补全。但在看直播时,如果画面频繁花屏、声音频繁断裂,观众会直接关掉——这是不可接受的用户体验。
TCP 保证了每一个字节都完整到达,视频解码器能正确工作,画面清晰流畅。
原因五:自适应码率非常容易实现
HLS 和 DASH 都天然支持自适应码率(ABR, Adaptive Bitrate)。
一个 m3u8 主播放列表可以包含多个不同码率的子播放列表:
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720
720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360
360p.m3u8
播放器可以根据当前的网络带宽,动态切换到不同质量的流。网速好就看 1080p,网速差就降到 360p。由于每个片段都是独立的 HTTP 请求,切换码率只需要在下一个片段时请求不同码率的文件即可,非常优雅。
这在 UDP 的流式传输中实现起来要复杂得多。
五、那 UDP 在直播中完全不用了吗?并不是。
实际上,一个完整的直播系统中,UDP 和 TCP 往往同时存在,只是用在不同的环节。
一个典型直播系统的完整链路
主播端 → 推流 → 源站服务器 → CDN 边缘节点 → 观众端播放器
我们分段来看:
第一段:主播推流到源站
主播的推流软件(如 OBS)通常使用 RTMP(Real-Time Messaging Protocol) 协议将视频流推送到平台的服务器。RTMP 底层是 TCP。
但也有平台开始使用基于 UDP 的推流协议(如 SRT、RIST),因为主播的上行网络往往不稳定,用 UDP 可以减少推流端的延迟和卡顿。
第二段:源站到 CDN 边缘节点(内部分发)
平台内部的服务器之间传输视频流,可能使用各种私有协议,有些基于 TCP,有些基于 UDP,取决于平台的技术选型。
第三段:CDN 边缘节点到观众(最后一公里)
这一段就是浏览器里看到的——HLS 的 m3u8 + m4s,走 HTTP/2 over TCP。这是面向几百万观众的大规模分发,用的是 TCP。
但如果观众需要连麦互动(比如 B 站直播的连麦功能),这个连麦的音视频流通常会走 WebRTC,底层是 UDP。因为连麦需要极低延迟的双向通信。
所以实际情况是:
- 大规模分发(一对多)→ TCP(HLS/DASH over HTTP)
- 实时互动(一对一/少对少)→ UDP(WebRTC/RTP)
两者可以在同一个直播间里同时存在。
六、近年来的新趋势:试图在 TCP 和 UDP 之间找到平衡
传统 HLS 有 3~10 秒延迟,这对某些场景还是太高了(比如电商直播带货、体育赛事直播、互动抽奖)。于是业界在不断探索降低延迟的方案:
1. LL-HLS(Low-Latency HLS)
苹果推出的低延迟版 HLS。核心思路是:不等一整个片段生成完毕,而是把一个片段再拆分成更小的部分片段(partial segment),一生成就推送。可以把延迟降到 2~3 秒。底层仍然是 HTTP/TCP。
2. LL-DASH(Low-Latency DASH)
与 LL-HLS 类似的思路,应用于 DASH 协议。
3. 基于 QUIC 的方案
QUIC 是 Google 开发的传输协议,底层跑在 UDP 上,但在 UDP 之上自己实现了可靠传输、拥塞控制、加密等功能。HTTP/3 就是基于 QUIC 的。
QUIC 的一个重要优势是解决了 TCP 的队头阻塞问题:在 QUIC 中,不同的数据流(stream)是独立的,一个流的丢包不会阻塞其他流。
一些平台已经开始实验用 HTTP/3(基于 QUIC/UDP)来传输 HLS/DASH 的直播流。从网络层看,这确实走的是 UDP,但从应用逻辑看,它的行为更像 TCP——数据仍然是可靠的、有序的。
4. WebTransport
这是一个新兴的 Web API,允许浏览器通过 QUIC 进行低延迟的数据传输,可以选择可靠模式或不可靠模式。未来可能会用于浏览器中的超低延迟直播。
七、总结:为什么看到的直播是 TCP
让我们把整个逻辑串起来:
-
"直播用 UDP"这句话来源于实时互动通信场景(视频会议、连麦),在那些场景下,极低延迟比数据完整性更重要,所以用 UDP。
-
在 B 站等平台观看的直播,属于"大规模单向直播分发"场景。这个场景的核心需求是:画质清晰、播放流畅、能支撑百万级并发观看。延迟在几秒之内是可以接受的。
-
HLS/DASH 协议把直播流切成小文件,通过普通的 HTTP 请求分发。这样做可以直接复用全球成熟的 CDN 基础设施,穿透各种防火墙和网络限制,支持自适应码率,保证数据完整性。
-
HTTP 跑在 TCP 上,所以看到的就是 TCP。HTTP/2(h2)进一步优化了性能(多路复用、头部压缩等),让这套方案更高效。
-
TCP 在这个场景下的延迟代价微乎其微,因为 HLS 本身的切片机制就有几秒的固有延迟,TCP 的重传时间在这个量级面前可以忽略不计。
所以,不是"视频直播应该用 UDP 但平台偷懒用了 TCP",而是不同的场景有不同的最优解。对于观众看到的那一段链路,TCP 就是正确的选择。
火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。
更多推荐
所有评论(0)