📹 第一章 流媒体与RTSP/RTP/RTCP简介
📄 一句话概括

RTSP 默认用持久连接:连一次,整场播放的信令都走这一条。 每条请求重连的话,光握手挥手就要九个包,比请求本身还重。

📝 本节和前面几节的关系

上一节把通用头讲完了,这一节讲这些报文跑在什么连接上。 连接这件事看着底层,但它直接决定了「延迟」和「断线怎么发现」—— 后者是监控里最难查的一类问题。

一、一条连接的完整生命周期

从建立到断开,一共七个动作、九个包:

阶段 包数 谁发起
三次握手 3 客户端
请求与响应 2 客户端发请求,服务端回
四次挥手 4 双方都可能发起

这九个包里,只有两个是「干活」的,其余七个都是开销。 所以一条连接用得越久,摊到每个请求上的开销越小。

这就是持久连接存在的全部理由——不是为了省资源,是为了省往返。

二、省了多少:算一遍

假设一场播放要发 N 条信令:

做法 包数 说明
每条重连 N × 9 完全不能接受
持久连接 3 + N × 2 + 4 握手挥手只付一次

N=5 时:45 包 vs 17 包,省 62%。 N=20 时:180 包 vs 47 包,省 74%。 N=60 时:540 包 vs 127 包,省 76%。

包数只是账面上的一半,真正值钱的是往返次数。 走公网一次往返按 30 毫秒算,每条请求多付一次往返, 60 条就是 1.8 秒——用户能明显感觉到「点了半天才有反应」。

三、连接什么时候会断

四种断法,前两种是正常的,后两种要靠自己发现:

断法 谁发起 怎么发现
发完 TEARDOWN 客户端 自己知道
Session 超时 服务端 下条请求回 454
设备重启 对方 TCP 可能还没报错
网线拔了 网络 要等 TCP 超时

后两种最阴:TCP 连接在协议栈看来还是「已建立」,你往里面写数据也不报错(数据进了发送缓冲), 但对面永远不回。 默认的 TCP 重传要试好几分钟才放弃,这期间程序毫无察觉。

所以播放器必须有应用层看门狗:多久没收到任何响应/数据,就主动断掉重连。 这个时长要比业务能忍的极限短——监控一般给 5 到 10 秒。

四、TCP 还是 UDP

这里的「TCP 还是 UDP」问的不是媒体,是信令。

TCP UDP
RTSP 信令 唯一选择 不支持
RTP 媒体 可选(穿墙时用) 默认

信令只能走 TCP:它要求可靠、有序、不丢,而 UDP 一样都不保证。 媒体默认走 UDP:它要求快,宁可丢也不要等。

这条分工是 RTSP 架构的根,所有「信令通了但没画面」「画面有但控不了」的问题, 都是因为这两条通道的独立性。

五、动手 Demo:一条 TCP 撑一场播放,比每次重连省多少

这段把「每条重连」和「持久连接」的包数算出来,对比省了多少。 注意省的比例随请求数上升而上升——因为固定开销被摊薄了。

for n in (5, 20, 60):
    short = n * 9                 # 每条请求重连:9 个包
    keep = 3 + n * 2 + 4          # 持久:握手 + 请求响应 + 挥手
    print(n, short, keep, (short - keep) * 100.0 / short)

实跑输出:

--------------------------------------------------------------------
一条 TCP 撑一场播放,比每次重连省多少
--------------------------------------------------------------------
**RTSP 默认用持久连接:连一次,整场播放的几十条信令都走这一条。**
  要是每条请求都重连,光握手挥手就把开销吃光了。

**先数一次 TCP 连接的包:**

  阶段           包数     谁发给谁
  ------------------------------------------------
  三次握手       3        SYN/SYN+ACK/ACK
  请求与响应     2        请求 1 个,响应 1 个
  四次挥手       4        FIN/ACK/FIN/ACK
  合计           9        —

   5 条请求:短连接  45 个包,持久连接  17 个包,**省掉 28 个(62%)。**
  20 条请求:短连接 180 个包,持久连接  47 个包,**省掉 133 个(74%)。**
  60 条请求:短连接 540 个包,持久连接 127 个包,**省掉 413 个(76%)。**

  这里的账只算了包数。**实际更值钱的是「少一次往返」**:
  走公网往返按 30 毫秒算,短连接每条请求多付 30 毫秒,60 条就是 1.8 秒。

**连接什么时候断:**
  情形                 连接状态
  ---------------------------------------------------
  TEARDOWN 之后        客户端主动断
  Session 超时         服务端主动断
  设备重启/网络断     谁都收不到,只能靠保活发现

  **第三条最阴**:TCP 已经断了,但你的程序还在 sleep 等包,看起来一切正常,
  实际上画面三分钟没动过。
  所以播放器必须有「多久没收到包就重连」的看门狗。

三个比例分别是 62%、74%、76%,越来越高但趋于上限。 上限是多少? 算一下就明白:N 很大时短连接是 9N,持久是 2N, 极限省 78%——因为三次握手加四次挥手那 7 个包摊到无穷多条请求上就不值钱了。

但包数不是重点,往返次数才是。 短连接每条请求多一次握手往返加一次挥手段,公网 30 毫秒一次的话,60 条请求就是三秒多的纯等待。 这就是为什么所有 RTSP 客户端默认都用长连接。

还有一个更实际的考虑:设备端的连接数是有限的。 一台摄像机可能只允许 4 到 16 条并发 RTSP 连接,频繁重连很容易撞上「连接数已满」, 表现为随机失败。 这类问题的特征是「有时好有时坏」,因为要看上一批连接释放了没有。

30 秒实验

  1. 抓一次完整的播放,数一下整场用了几条 TCP 连接。
  2. 算一下你的场景(比如 20 条信令)用持久连接能省多少个包。
  3. 把网线拔掉,看播放器多久才发现——这个时间就是它的看门狗阈值。

常见误区

  1. 以为每个请求都要新建连接。 RTSP 默认是持久连接,整场播放的信令都走同一条。
  2. 以为 TCP 断了程序会立刻知道。 拔网线的情况下,协议栈可能几分钟才报错, 应用层必须自己设看门狗。
  3. 以为信令也能走 UDP。 不能。RTSP 只跑 TCP,UDP 那条路是 RTP 媒体专用的。
自测三问(点开对答案) 1. 持久连接省下来的主要是包数还是往返次数? —— 往返次数。包数省 60% 到 78%,但公网上每次往返 30 毫秒的等待才是真正能感觉到的部分。 2. 拔掉网线,为什么程序往往不会立刻发现? —— TCP 连接在协议栈看来还是已建立状态,写数据进发送缓冲不报错,重传要试好几分钟才放弃。 所以需要应用层看门狗。 3. 频繁重连还有什么隐性代价? —— 设备的并发连接数有上限(常见 4 到 16 条),重连太快容易撞上「连接数已满」,表现为随机失败。

下一节讲扩展:Require 和 Supported 怎么谈条件,为什么是 551 不是 501。

相关笔记