🎬 第十一章 SRS搭建直播平台
📄 一句话概括

--with-rtc 一个开关,牵出加密库、SRTP、UDP 端口三样东西。 前两样编不过会立刻发现,第三样要等观众连上来才暴露。

📝 本节和前面几节的关系

11.4 讲的都是 TCP 那一侧,这一节换成 UDP。 11.5.2 推流还是 RTMP,11.5.3 才用 WebRTC 播。

一、一条开关,三层依赖

./configure --with-rtc 看着只是加一个参数,实际牵动三样:

① OpenSSL:DTLS 加密与证书指纹,缺了直接编不过。 ② libsrtp:SRTP 加密媒体流,缺了编译期报找不到头文件。 ③ UDP 端口:媒体走 UDP 不走 TCP,防火墙没放行就白配。

这三层里最容易漏的是第三层。 前两层是编译期问题,编不过会立刻发现; 第三层是运行期问题,服务器自己觉得一切正常,就是观众画面出不来。

编译命令大概长这样:

./configure --with-rtc --with-ssl --with-hls --with-http-server
make -j4
./objs/srs -c conf/rtc.conf

编完一定要看 objs/srs 有没有变大。 带 RTC 的版本明显大一圈,这是最直观的「编进去了」的证据。

二、真查加密库与候选端口

DTLS 要求 OpenSSL 1.1.1 以上,本机实测是 3.5.7,够用。 但要注意:这个版本号是 Python 自带的那份 OpenSSL, 编译 SRS 用的是系统里的 openssl-devel,两者可能不是同一个。 真要确认,得在命令行敲 openssl version。

候选端口也要提前看: WebRTC 要在 SDP 里告诉对方「往哪个 IP、哪个端口发」。 本机 UDP 8000 到 8009 十个端口全都能绑,说明没被别的进程占着。 但「能绑」不等于「外部能访问」,云服务器还要单独放行 UDP 安全组。

这一节最实用的判断是这一条: 先在本机把所有候选 IP 列出来,看有几个是回环。 回环地址放进 SDP 没有任何意义——观众那边访问不到 127.0.0.1。 「本机能看、别人看不了」十次有八次是这个原因。

三、候选地址还有优先级

SDP 里每个候选都带一个优先级数字,公式是固定的: 优先级 = 类型偏好 × 2^24 + 本地偏好 × 2^8 + (256 - 分量)。

类型偏好只有四档:host 126、prflx 110、srflx 100、relay 0。 代入之后得到四个固定值:host 是 2130706431,relay 只有 16777215。 差了整整一百多倍。

这个排序就是 NAT 穿透的顺序: 先试直连(host),不通再打洞(srflx),最后才走中继(relay)。 能用直连就不用中继——中继要多绕一圈服务器,延迟和带宽都吃亏。 所以看到 SDP 里最后选中 relay,通常意味着网络环境比较差。

四、动手 Demo:编一个带 WebRTC 的 SRS,多要什么

先查依赖,再列候选地址与端口, 最后把四个类型偏好的优先级算出来。

import ssl, socket

print(ssl.OPENSSL_VERSION)          # DTLS 要 1.1.1 以上

# 候选 IP:本机有几个就得列几个
ips = set()
for info in socket.getaddrinfo(socket.gethostname(), None):
    ips.add(info[4][0])
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("223.5.5.5", 53))       # 只为拿出口地址,不发包
ips.add(s.getsockname()[0])

# 候选端口:能绑 = 没被占
ok = []
for pt in range(8000, 8010):
    u = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        u.bind(("0.0.0.0", pt))
        ok.append(pt)
    except OSError:
        pass
    u.close()

# 优先级公式
for name, tp in (("host", 126), ("prflx", 110),
                 ("srflx", 100), ("relay", 0)):
    print(name, (tp << 24) + (65535 << 8) + 255)

实跑输出:

--------------------------------------------------------------------
编一个带 WebRTC 的 SRS,多要什么
--------------------------------------------------------------------
**① 一条开关,三层依赖**

  **`./configure --with-rtc` 看起来只是加一个参数,实际牵动三样东西。**

  多出来的     作用                     缺了会怎样
  ------------------------------------------------------------------
  OpenSSL      DTLS 加密与证书指纹      编不过,或握手直接失败
  libsrtp      SRTP 加密媒体流          编译期报找不到头文件
  UDP 端口     媒体走 UDP,不走 TCP     防火墙没放行,能连不能看

  **这三层里最容易漏的是第三层。**
  **前两层是编译期问题,编不过会立刻发现;**
  **第三层是运行期问题,服务器自己觉得一切正常,就是观众画面出不来。**

  **编译命令大概是:**

    ./configure --with-rtc --with-ssl --with-hls --with-http-server
    make -j4
    ./objs/srs -c conf/rtc.conf

**② 真查本机的加密库够不够**

  **DTLS 要 OpenSSL 1.1.1 以上,先看版本。**

  项目             实测值                       DTLS 够不够
  -------------------------------------------------------------
  OpenSSL 版本     OpenSSL 3.5.7 9 Jun 2026     够
  版本号数值       3.5                          -
  TLS 1.3 支持     有                           -

  **这台机器是 3.5.7,按门槛算够用。**
  **注意:Python 里的 OpenSSL 和编译 SRS 用的不一定是同一个。**
  **真编译时要看 `openssl version` 与 `openssl-devel` 包,**
  **不是这里查到的这个号。这一条只能当参考。**

**③ 真枚举候选地址与 UDP 端口**

  **WebRTC 要在 SDP 里告诉对方「往哪个 IP、哪个端口发」。**
  **这些 IP 就是候选地址,本机有几个就得列几个。**

  候选 IP           来源         能用吗
  -------------------------------------------
  127.0.0.1         回环         只在本机
  192.168.3.152     网卡地址     可以

  **本机一共 2 个 IPv4 地址,其中 1 个是回环。**
  **回环地址放进 SDP 没有意义:观众那边访问不到 127.0.0.1。**
  **这就是「本机能看、别人看不了」最常见的原因。**

  端口范围          能绑几个     说明
  ----------------------------------------------------------
  UDP 8000~8009     10 个        能绑 = 没被别的进程占着

  **端口能绑不代表外部能访问,防火墙是另一回事:**
  **云服务器要单独放行 UDP,安全组里那条规则经常被忘掉。**

**④ 候选地址还有优先级**

  **SDP 里每个候选都带一个优先级数字,公式是固定的:**
  **`优先级 = 类型偏好 × 2^24 + 本地偏好 × 2^8 + (256 - 分量)`。**

  类型      类型偏好     优先级数值     含义
  --------------------------------------------------------
  host      126          2130706431     本机地址,直连
  prflx     110          1862270975     对端反射
  srflx     100          1694498815     STUN 反射
  relay     0            16777215       TURN 中继

  **host 排在最前,relay 排在最后:**
  **能用直连就不用中继,中继要多绕一圈服务器,延迟和带宽都吃亏。**
  **这也是 NAT 穿透的顺序:先试直连,不通再打洞,最后才走中继。**

本机两个 IPv4 地址,其中一个是回环,后者放进 SDP 没有意义。 UDP 8000 到 8009 十个端口全能绑,说明没有冲突。 四个优先级:2130706431、1862270975、1694498815、16777215。 host 与 relay 差一百多倍,这就是「先直连后中继」的数值依据。

30 秒实验

  1. 把 UDP 范围改成 8000 到 8001,猜还剩几个能绑——还是两个,除非别的进程占着。
  2. 把 origin 里的 IP 换成回环,看优先级变不变——不变,优先级只看类型,不看地址。
  3. 用 openssl version 查系统那份,和 Python 报的比一比——可能不一样,编译看的是系统那份。

常见误区

  1. 「加了 --with-rtc 就能用」——还要开 UDP 端口,否则能连不能看。
  2. 「relay 优先级高」——最低,它是最后的退路。
  3. 「回环地址也能当候选」——能当,但只有本机访问得到。
自测三问(点开对答案) 1. `--with-rtc` 会多要哪三样? —— **OpenSSL、libsrtp、UDP 端口。** 2. DTLS 要求 OpenSSL 什么版本? —— **1.1.1 以上。** 3. host 与 relay 的优先级差多少倍? —— **约一百多倍**,所以永远先试直连。

相关笔记