1. 为什么WebRTC播放会失败?

最近在帮朋友部署SRS视频服务器时遇到一个典型问题:用Docker启动服务后,RTMP推流正常,但WebRTC始终无法播放。经过排查发现,这其实是端口映射不一致导致的经典问题。很多新手在使用Docker部署SRS时都会踩这个坑,今天我就把完整排查过程和解决方案分享给大家。

先说说问题现象:当我们通过docker run -p 1936:1935 -p 8001:8000这样的命令启动容器时,虽然视频能正常录制到宿主机目录,但用SRS自带的播放器测试WebRTC流时,控制台会报"ICE连接失败"的错误。这其实是因为Docker的端口映射机制和WebRTC的协商机制产生了冲突。

2. 端口映射不一致引发的连锁反应

2.1 Docker端口映射的本质

Docker的-p参数实现的是NAT端口转发,其工作流程是这样的:

  1. 外部请求到达宿主机的1936端口
  2. Docker引擎将请求转发到容器的1935端口
  3. 容器内SRS服务处理请求

问题就出在WebRTC的ICE协商阶段。当客户端请求播放时,SRS服务器会根据配置文件中的listen 1935和listen 8000生成SDP描述。这个描述告诉客户端:"请连接我的1935和8000端口"。但客户端实际需要连接的却是宿主机的1936和8001端口,这就导致了连接失败。

2.2 WebRTC的ICE协商过程

WebRTC建立连接时需要完成ICE协商,主要包含这几个步骤:

  1. 客户端请求播放时,服务器返回SDP描述
  2. SDP中包含候选地址(candidate)和端口信息
  3. 客户端尝试与这些地址建立连接

当端口映射不一致时,SDP中的端口(1935/8000)与实际可访问的端口(1936/8001)不匹配,ICE协商就会失败。这就好比有人告诉你"请到301房间找我",但实际他却在302房间等你,自然找不到人。

3. 两种配置方案的对比分析

3.1 错误配置示例

# 错误示范:内外端口不一致
docker run -p 1936:1935 -p 8001:8000/udp ...

对应的SRS配置:

listen 1935;
rtc_server {
    listen 8000;
    candidate 公网IP;
}

这种配置会导致:

  • RTMP推流正常(因为客户端直接使用1936端口)
  • 视频录制正常(不依赖端口映射)
  • WebRTC播放失败(ICE协商端口不匹配)

3.2 正确配置方案

# 正确做法:保持内外端口一致
docker run -p 1936:1936 -p 8001:8001/udp ...

对应的SRS配置:

listen 1936;
rtc_server {
    listen 8001;
    candidate 公网IP;
}

关键调整点:

  1. Docker映射保持内外端口一致
  2. SRS配置文件改用宿主机端口
  3. 确保防火墙开放相应端口

4. 完整部署流程与验证

4.1 正确部署步骤

  1. 启动容器(注意端口一致):
docker run -d --name srs \
    -p 1936:1936 -p 1985:1985 \
    -p 8080:8080 -p 8001:8001/udp \
    -v /path/to/dvr:/usr/local/srs/static/DVR-video \
    registry.cn-hangzhou.aliyuncs.com/ossrs/srs:4 \
    ./objs/srs -c conf/rtmp2rtc.conf
  1. 修改配置文件:
listen 1936;
rtc_server {
    enabled on;
    listen 8001;
    candidate 你的公网IP;
}
  1. 重启服务使配置生效:
docker restart srs

4.2 效果验证方法

  1. 推流测试:
ffmpeg -re -i test.mp4 -c copy -f flv rtmp://服务器IP:1936/live/stream
  1. 播放验证:
  • 访问http://服务器IP:8080/players/rtc_player.html
  • 输入流地址webrtc://服务器IP:1936/live/stream
  • 观察视频是否能正常播放
  1. 检查ICE连接:
  • 浏览器开发者工具查看WebRTC连接状态
  • 确认使用的端口是8001而非8000

5. 常见问题排查指南

5.1 端口占用问题处理

如果遇到端口冲突,建议:

  1. 使用netstat -tulnp查看端口占用情况
  2. 选择未被占用的端口组合,例如:
    • 1936 → 1936
    • 8001 → 8001
    • 8081 → 8081

5.2 防火墙配置要点

确保宿主机防火墙放行以下端口:

  • TCP: 1936(RTMP)
  • UDP: 8001(WebRTC)
  • TCP: 1985(HTTP API)
  • TCP: 8080(Web管理)

对于云服务器,还需要配置安全组规则。我曾经遇到过因为忘记开安全组UDP端口,排查了整整一个下午的惨痛经历。

5.3 其他可能的问题

  1. NAT穿透问题:如果服务器位于多层NAT后,需要配置正确的candidate地址
  2. TURN服务器:在复杂网络环境下可能需要配置TURN服务器
  3. SRS版本差异:不同版本配置项可能有细微差别,建议使用最新稳定版

6. 深入理解端口映射机制

6.1 Docker网络模式对比

Docker支持多种网络模式,部署SRS时需要注意:

网络模式特点适用场景
bridge默认模式,NAT转发单机部署
host直接使用宿主机网络需要避免端口映射问题
overlay多主机网络集群部署

对于大多数场景,使用bridge模式并保持端口一致是最佳选择。

6.2 WebRTC端口使用规律

WebRTC通信需要以下端口:

  • 3478 UDP:STUN服务
  • 49152-65535 UDP:动态分配的媒体端口
  • 配置的UDP端口(如8001):应用层通信

因此除了配置的8001端口外,还需要确保服务器的UDP端口范围开放。

7. 高级配置技巧

7.1 多实例部署方案

当需要部署多个SRS实例时,可以这样配置:

# 实例1
docker run -p 1936:1936 -p 8001:8001/udp ...

# 实例2
docker run -p 1937:1937 -p 8002:8002/udp ...

每个实例需要:

  1. 使用独立的端口组
  2. 配置独立的存储目录
  3. 修改对应的配置文件

7.2 使用docker-compose管理

推荐使用docker-compose.yml来管理部署:

version: '3'
services:
  srs:
    image: registry.cn-hangzhou.aliyuncs.com/ossrs/srs:4
    ports:
      - "1936:1936"
      - "8001:8001/udp"
    volumes:
      - ./dvr:/usr/local/srs/static/DVR-video
    command: ["./objs/srs", "-c", "conf/rtmp2rtc.conf"]

这样部署和管理都更加方便,也减少了手动输入命令出错的可能性。

8. 性能优化建议

8.1 内核参数调优

对于高并发场景,建议调整以下内核参数:

# 增加UDP缓冲区大小
sysctl -w net.core.rmem_max=26214400
sysctl -w net.core.wmem_max=26214400

# 增加文件描述符限制
ulimit -n 65535

8.2 SRS配置优化

在rtmp2rtc.conf中可以调整:

rtc_server {
    # 每个连接的工作线程
    worker_processes 4;
    # 心跳间隔
    heartbeat_timeout 30s;
    # 带宽限制
    max_bandwidth 100m;
}

这些参数需要根据实际服务器配置和业务需求进行调整。

Logo

邀请您加入社区

更多推荐