在直播和音视频分发这个领域摸爬滚打了几年,我最常被问到的不是“哪个播放器好用”,而是“怎么在Windows上快速搭一套流媒体服务”。大多数团队的开发机是Windows,测试环境又不想单独申请一台Linux服务器,这时候能在Windows本地直接跑起SRS,整个调试链路会顺畅很多。SRS(Simple Realtime Server)是目前使用率很高的开源流媒体服务器,支持RTMP、HTTP-FLV、HLS、WebRTC等主流协议,单机就能扛住高并发拉流。这篇文章是一份实际操作记录,从选型到部署、从推流到拉流、从配置到排坑,尽量把Windows环境下的坑一次说清楚。
1. 为什么要在Windows上部署SRS:场景与选型逻辑
1.1 SRS到底能干什么
很多刚接触音视频的同学会把SRS理解成一个“直播中转站”,其实它承担的工作远超转发。SRS的核心能力是协议转换和分发:推流端用RTMP推上来,播放端可能是RTMP、HTTP-FLV、HLS或者WebRTC,SRS负责把这些协议之间的差异抹平,让一套流同时喂给PC浏览器、移动端H5、小程序和电视盒子。
举个例子,你用OBS推RTMP流到SRS,SRS内部把流重新封装,对外同时提供FLV地址给网页播放器、HLS地址给苹果生态、WebRTC地址给低延迟场景。这个过程不需要推流端做任何改动,播放在哪个端、用什么协议,都是SRS根据配置自动处理的。
Windows环境下部署SRS最典型的场景有三个:第一,本地开发调试,前端写播放器、后端写推流逻辑,不想反复连远程服务器;第二,小型企业内网直播,比如培训、会议转播,并发量不大但要求稳定;第三,演示和POC验证,给客户展示私域直播方案,临时抱一台Windows机器也能撑起来。
1.2 Windows部署的三条路线怎么选
SRS本身是为Linux设计的高性能服务,官方推荐的生产环境也是Linux。但在Windows上跑,主流有三条路线:Docker Desktop容器化、WSL2(Windows子系统)、以及源码编译原生二进制。
我个人的建议非常明确:优先Docker Desktop。原因有几点,一是镜像开箱即用,SRS官方镜像把编译好的二进制和默认配置都打包好了,拉下来就能跑;二是隔离性好,SRS依赖的库、编译环境不会污染Windows系统;三是升级容易,换镜像tag相当于换版本,回滚也简单。WSL2方案适合那些不想装Docker、又确实需要Linux兼容环境的场景,性能接近原生,但网络和文件系统偶尔会有坑。源码编译原生二进制是最折腾的路,SRS官方并不为Windows维护二进制产物,需要自己解决编译环境、依赖库、信号处理等一堆问题,除非有特殊需求,否则不建议碰。
如果你只是想在Windows机器上快速验证SRS功能,别纠结,直接走Docker路线。后面我主要围绕这个方案展开,原生部署作为备选补充。
2. 环境准备与部署前的关键决策
2.1 硬件与系统要求
先说硬件。SRS本身比较轻,内存占用在几十兆到几百兆之间,真正吃资源的是推流和转封装时的CPU开销。如果是做开发测试,4核CPU、8G内存的机器绰绰有余;如果是内网小规模直播,建议16G内存以上,磁盘最好是SSD,因为HLS切片要频繁写文件。
Windows版本方面,Docker Desktop现在要求Windows 10 64位专业版/企业版/教育版(2004及以上)或Windows 11,且必须开启Hyper-V和虚拟化。家用版Windows 10也能装Docker Desktop,但需要额外处理一些依赖,建议直接用专业版省心。
检查虚拟化是否开启,最简单的方式是打开任务管理器,性能标签页里能看到“虚拟化:已启用”。如果没有,需要进BIOS开启Intel VT-x或AMD-V,这一步不做,Docker Desktop装了也起不来。
2.2 端口规划与网络拓扑
SRS默认会用到三个端口:1935是RTMP推流和拉流端口,1985是HTTP API端口(管理接口),8080是HTTP服务端口(FLV/HLS/WebRTC等走这个)。这只是默认值,可以改,但建议开发环境保持默认,减少配置心智负担。
部署前先确认这些端口没有被占用。Windows下用一条命令就行:
netstat -ano | findstr "1935 1985 8080"如果端口被占用了,后面会专门讲排查方法。这里先记住一个原则:SRS涉及的端口必须同时在Windows防火墙和Docker端口映射两层放行,很多人最后发现“容器起来了但连不上”,八成是防火墙没放行。
网络拓扑方面,如果只是本机测试,推拉流都指向127.0.0.1即可。如果要让局域网内其他设备访问,需要保证Windows机器的IP是固定的,或者至少能通过主机名访问,否则手机会员设备随时可能找不到服务器。建议在路由器上做DHCP静态绑定,或者直接在Windows网络设置里指定静态IP。
2.3 Docker Desktop安装要点
Docker Desktop安装本身没什么技术含量,但有几个细节值得注意。安装完成后首次启动,会提示是否启用WSL2后端,这一步务必选择“使用WSL 2”,否则会退回Hyper-V旧方案,性能和资源占用都很差。
安装完成后打开PowerShell验证:
docker version docker compose version如果两条命令都能正常输出版本信息,Docker环境就准备好了。如果docker命令报错,大概率是Docker Desktop服务没有启动,去系统托盘找到鲸鱼图标右键启动即可。
国内网络环境下,拉取Docker镜像可能会比较慢甚至超时。解决办法是配置镜像加速源,在Docker Desktop的Settings里找到Docker Engine,编辑JSON配置,加入registry-mirrors字段,然后应用并重启Docker。这一步不是可选项,我见过太多人卡在镜像拉取上。
3. 主推方案:Docker跑SRS全流程
3.1 拉取镜像与初始化
SRS官方镜像的命名是ossrs/srs,目前主稳定版本是5.0系列。拉取命令很简单:
docker pull ossrs/srs:5拉取完成后可以先快速跑一个默认实例验证镜像是否正常:
docker run -d --name srs-test -p 1935:1935 -p 1985:1985 -p 8080:8080 ossrs/srs:5启动后访问http://localhost:8080,如果能看到SRS的默认提示页面,说明镜像和服务都正常。这里要注意,默认配置下SRS并没有开启HLS和HTTP-FLV,网页里显示的只是静态文件页面,真正的流媒体能力需要用自己的配置文件覆盖默认配置。
验证完毕后把这个测试容器删掉,我们开始正式配置:
docker stop srs-test && docker rm srs-test3.2 编写第一个可用的配置文件
SRS的配置格式类似Nginx,核心逻辑是全局配置加vhost虚拟主机配置。下面这份配置是我平时调试用的最小可用配置,覆盖了RTMP、HTTP-FLV和HLS三种协议:
listen 1935; max_connections 1000; daemon off; srs_log_tank console; http_api { enabled on; listen 1985; } http_server { enabled on; listen 8080; dir ./objs/nginx/html; } vhost __defaultVhost__ { http_remux { enabled on; mount [vhost]/[app]/[stream].flv; } hls { enabled on; hls_path ./objs/nginx/html; hls_fragment 2; hls_window 10; } }解释几个关键点。daemon off很关键,Docker容器里进程必须在前台运行,否则容器会立刻退出。http_remux开启后,RTMP流会自动转换成HTTP-FLV流,这样播放器可以不用Flash直接拉流。hls_fragment 2表示每个HLS切片2秒,hls_window 10表示播放窗口10秒,这个参数组合适合低延迟场景,但要注意切片越小,磁盘写入频率越高。
在Windows上,配置文件的保存路径建议放在一个专门目录,比如D:\srs\conf\srs.conf。这样做的好处是后续升级镜像、迁移数据都方便,避免容器删除后配置丢失。
3.3 启动、验证与自动恢复
配置文件准备好了,正式启动容器:
docker run -d --name srs \ -p 1935:1935 \ -p 1985:1985 \ -p 8080:8080 \ -v D:/srs/conf/srs.conf:/usr/local/srs/conf/srs.conf \ -v D:/srs/html:/usr/local/srs/objs/nginx/html \ --restart always \ ossrs/srs:5这里做了两个目录挂载:一个是配置文件,一个是HLS切片和静态文件目录。--restart always意味着Docker服务启动时容器会自动拉起,Windows重启后不需要手动操作。
启动后建议立刻做两个验证。第一,看容器日志:
docker logs srs日志里出现start server successfully之类的字样说明SRS已经启动。第二,测试API接口是否存活:
curl http://localhost:1985/api/v1/versions如果返回一个包含版本号的JSON,说明SRS的HTTP API正常工作。到这里,SRS容器已经跑起来了,但真正的直播链路还要配合推流和播放工具来验证。
4. 备选方案:Windows原生二进制部署
4.1 获取二进制与依赖说明
虽然Docker是首选,但有些场景确实没法用容器:比如公司安全策略禁止安装Docker Desktop,或者机器配置太低跑不动Hyper-V。这时候可以考虑WSL2方案,或者找第三方编译好的Windows原生二进制。
先说WSL2方案。在PowerShell管理员模式下执行:
wsl --install重启后进入WSL2环境,然后按照Linux的方式安装SRS即可。需要注意的是WSL2的网络模式默认是NAT,WSL内部的1935端口默认并不能直接被局域网访问,需要在Windows侧做端口转发:
netsh interface portproxy add v4tov4 listenport=1935 listenaddress=0.0.0.0 connectport=1935 connectaddress=127.0.0.1这条命令把Windows的1935端口转发到WSL2内部的SRS服务,原理上就是一个轻量反代。同理1985、8080都要做一遍。
至于Windows原生二进制,SRS官方没有分发exe版本,网上能找到的第三方编译包来源五花八门,安全性无法保证。如果你一定要用,建议选择开源社区维护、有编译脚本的版本,并在隔离环境先跑一遍做安全检查。记住一个原则:跑流媒体服务器的机器,安全性比性能更重要。
4.2 配置和启动
WSL2方案下,SRS的启动命令和Linux完全一致。先编译或下载解压,然后:
./configure --full make -j4 ./objs/srs -c conf/srs.conf编译过程耗时较长,依赖库也较多,所以WSL2方案通常适合那些需要改SRS源码做二次开发的场景。如果只是要跑起来用,Docker依然是最高效的选择。
启动后验证方式和前面一样,看日志、测API。要特别注意WSL2里SRS的IP,可以通过hostname -I查看WSL2的IP地址,但Windows访问WSL2的服务通常用127.0.0.1就行,WSL2自带了端口转发能力。
4.3 开机自启与守护
原生方案最大的痛苦是进程守护。Docker有restart always,原生WSL2里的SRS如果崩了,不会自动拉起。解决办法是在WSL2的/etc/crontab里加一条:
*/1 * * * * root pgrep -f "objs/srs" > /dev/null || /usr/local/srs/objs/srs -c /usr/local/srs/conf/srs.conf每分钟检查一次SRS进程是否存在,不存在就拉起。这是最朴素的守护方式,够用但不优雅。更可靠的方式是用systemd,但在WSL2里配置systemd比较麻烦,建议直接用cron方案。
Windows重启后WSL2默认不会自动启动,需要在启动目录放一个脚本调用wsl -d <发行版名称> -u root /usr/local/srs/objs/srs -c /usr/local/srs/conf/srs.conf。这些细节比较多,如果你不是对“非Docker”有硬性要求,我还是建议回到Docker路线。
5. 核心配置深度解析:从能跑到能商用
5.1 必配基础项
前面那份简单配置能跑通,但离“能用”还有距离。以下几个配置项是基础中的基础。
max_connections控制最大并发连接数,默认值可能只够几十个连接。商用场景要根据实际并发估算,一般按“并发播放数+推流数+API查询余量”来计算。保守做法是设置为预期峰值的1.5倍,比如预期1000路并发播放,就设为1500。
srs_log_tank决定日志输出方式,开发环境用console方便看docker logs,生产环境建议改为file并指定log_file路径。日志级别控制在info足够,debug级别的日志量会非常大,生产环境不要开。
注意:修改配置后不要直接kill容器进程,应该用SRS的API优雅重启。执行
curl -X POST http://localhost:1985/api/v1/restart,让SRS自己重载新配置,避免中断正在进行的直播。
5.2 直播协议联动逻辑
SRS最常用的四种协议各有分工:RTMP是输入协议,也兼容老播放器;HTTP-FLV延迟低、穿透性好,是PC网页播放的首选;HLS兼容性最好,苹果设备和微信内嵌浏览器只能用HLS;WebRTC延迟最低,适合连麦和互动场景。
协议联动靠的是http_remux和hls两个模块。http_remux开启后,SRS会在RTMP流进来时自动生成FLV流,不需要额外登记,播放路径和推流路径是对应关系:推流到rtmp://ip/live/livestream,FLV播放地址就是http://ip:8080/live/livestream.flv。
HLS的生成逻辑是定时把RTMP流切成ts文件并维护m3u8索引。hls_fragment决定切片时长,hls_window决定播放器能看到多长的时间窗口。如果对延迟要求高,hls_fragment可以设成1秒,但磁盘碎片会比较多;如果对稳定性要求高,设成4到6秒更稳。
5.3 鉴权与防盗链
流媒体服务器一旦暴露在公网,很快就有人蹭你的带宽。SRS的推荐做法是配合HTTP回调做鉴权,也叫on_publish回调。推流端在推流URL上附带参数,SRS在收到推流请求时回调你的业务服务器,只有业务服务器返回允许,推流才会继续。
配置如下:
vhost __defaultVhost__ { http_hooks { enabled on; on_publish http://127.0.0.1:8080/api/auth/publish; on_play http://127.0.0.1:8080/api/auth/play; on_stop http://127.0.0.1:8080/api/auth/stop; } }回调URL里带上具体业务服务器的地址,业务接口收到请求后校验参数,返回0表示允许,返回非0表示拒绝。这个机制的优点是鉴权逻辑完全由业务控制,SRS本身只做转发,灵活性很高。
防盗链方面,常用手段是Referer校验和自定义Header校验。但HTTP-FLV的URL是明文,Referer和Header都容易被伪造,真正的防盗还是靠token动态鉴权。简单说就是播放URL里带一个有效期token,SRS通过回调验证token的有效性。
5.4 日志与性能参数
日志配置容易被忽略,但排查问题时没日志等于瞎猜。建议明确指定日志级别和文件路径:
srs_log_tank file; srs_log_file ./objs/srs.log; srs_log_level info;日志文件会持续增长,需要配合日志切割策略。SRS内置了log_tank的file模式,但不提供自动轮转,我通常借助Docker的日志轮转能力来限制大小:
docker run ... --log-opt max-size=100m --log-opt max-file=3 ...性能参数方面,max_connections之外还有send_buffer_size和receive_buffer_size,默认值通常够用。如果网络状况比较差,可以适当调大接收缓冲,减少丢包导致的卡顿。SRS的并发能力很大程度上取决于带宽和磁盘IO,不要盲目调大连接数,先把带宽瓶颈解决。
6. 推拉流全链路实操验证
6.1 用OBS推流
SRS起来之后,推流工具我用得最多的是OBS,免费、跨平台、生态好。OBS的设置里找到“设置-直播”,服务选“自定义”,服务器地址填:
rtmp://127.0.0.1/live推流码填一个自定义流名称,比如test123。这里有个关键点:OBS的服务器地址和推流码最终拼成完整地址是rtmp://127.0.0.1/live/test123,对应SRS里的app是live,stream是test123。app和stream的名字决定播放时URL的路径,所以要规划好命名。
点击“开始推流”后,OBS界面的状态会变成“直播中”,并且能看到上传速度。如果推流失败,第一时间看SRS日志:
docker logs srs --tail 20常见的报错是no available stream或者连接被拒,前者说明SRS没收到流,后者说明网络或端口问题。
6.2 三种播放方式验证
推流成功只是第一步,关键是播放端能拉下来。我在验证时一般同时测三条路径:
RTMP播放用ffplay:
ffplay rtmp://127.0.0.1/live/test123HTTP-FLV播放用ffplay或VLC:
ffplay http://127.0.0.1:8080/live/test123.flvHLS播放最简单,浏览器直接访问:
http://127.0.0.1:8080/live/test123.m3u8注意HLS的URL和FLV略有不同,HLS路径由hls_path和hls_fragment共同决定,访问的是live/test123.m3u8而不是test123.hls。
播放时如果把127.0.0.1换成Windows机器在局域网里的IP,就可以在手机或其他电脑上测试跨设备播放。如果手机访问不了,立即查防火墙。
6.3 链路延迟压测要点
验证完基本播放,还要测一下延迟。方法很简单:推流端放一个秒表或者计时画面,播放端拍照对比时间差。不同协议的延迟预期大致是:HTTP-FLV 2到5秒,HLS 4到10秒,WebRTC 0.5到1秒。
如果实测HLS延迟超过预期,优先检查hls_fragment和hls_window的配置。切片是分批发布的,播放器加载m3u8也要时间,所以HLS天然比FLV延迟高。如果追求低延迟,建议用HTTP-FLV,并且把GOP(关键帧间隔)设置为2秒以内。OBS的“输出-视频编码器”里可以设置关键帧间隔,不设置的话默认可能大于4秒,直接影响播放延迟。
7. 高频问题与排查实录
7.1 防火墙导致的外部无法访问
这是Windows部署SRS遇到最多的问题。容器内部正常、本机访问正常、但局域网其他设备连不上,十有八九是Windows Defender防火墙拦截了端口。
解决办法是添加入站规则,PowerShell管理员执行:
netsh advfirewall firewall add rule name="SRS RTMP" dir=in action=allow protocol=TCP localport=1935 netsh advfirewall firewall add rule name="SRS API" dir=in action=allow protocol=TCP localport=1985 netsh advfirewall firewall add rule name="SRS HTTP" dir=in action=allow protocol=TCP localport=8080如果用了端口转发,还需要同时放行转发时用到的端口。要注意Docker Desktop的端口映射是绑定在所有网卡上的,理论上局域网可以直接访问宿主机的映射端口,但防火墙规则必须先放行。
7.2 端口占用冲突
启动容器时如果报错类似port is already allocated,说明宿主机端口被其他程序占用。解决办法要么停掉占用程序,要么换端口映射。换端口映射的方式:
docker run -d -p 1936:1935 -p 1986:1985 -p 8081:8080 ...宿主机的1936映射到容器里的1935,外部访问用1936,SRS内部仍然监听1935。这个方案适合不想动其他服务、只想临时跑SRS的场景。但注意,改端口后推流地址和拉流地址都要跟着变,容易把人绕晕,非必要不折腾。
7.3 磁盘写满
HLS切片是持续写文件的,如果直播长时间进行、没有及时清理旧切片,磁盘空间会被慢慢占满。配置hls_window只能控制播放窗口,不能自动删除已经没有播放器引用的旧切片。
解决办法有三个层面:第一,把hls_path挂载到一个独立的、空间充足的磁盘目录;第二,写一个定时清理任务,删除超过N小时的ts文件;第三,如果业务允许,直接关闭HLS输出,只保留FLV转发,HLS比较吃磁盘IO。
7.4 延迟突然增大
延迟无故变大的常见原因是网络拥塞和GOP设置不合理。Windows机器如果同时承担推流和缓存转发,CPU和带宽都会成为瓶颈。先看任务管理器里的网络占用,再看SRS日志里有没有丢包或超时报错。
GOP方面,如果推流端的关键帧间隔太长,播放器必须等下一个关键帧才能起播,表现就是“黑屏几秒”和“切换频道慢”。建议把编码器的GOP设为1到2秒,具体在OBS的“输出”设置里可以调。
7.5 重启后容器没有自动恢复
--restart always只保证Docker守护进程启动后会自动拉起容器,如果Docker Desktop本身没有开机启动,那么Windows重启后SRS依然不会运行。需要在Docker Desktop的设置里勾选“Start Docker Desktop when you sign in”。
另外,如果容器启动依赖的挂载目录在重启后不存在了(比如D盘没挂载上),容器也会启动失败。建议在配置挂载时使用绝对稳定的路径,避免使用U盘、网络映射盘这类不稳定的存储位置。
8. 最后分享几个实用心得
SRS这套系统我前后用了不短时间,印象最深的一点是配置项的坑通常不在配置本身,而在环境差异。同样的配置文件,Docker部署和WSL2部署的路径映射完全不同,新手经常栽在这里。
一个实用技巧:善用SRS的HTTP API。除了版本查询,还能查询在线推流信息、踢人下线、动态查询vhost状态。比如在线流列表接口:
curl http://localhost:1985/api/v1/streams/返回的JSON里能看到当前有多少路流、每一路的客户端数量、码率等信息,排查直播异常比翻日志快得多。
最后再说一句,如果只是个人测试,装Docker Desktop可能显得“重”,但一旦你需要在同一台机器上同时跑SRS、转码工具、录制服务,Docker的统一管理优势就出来了。环境隔离、一键重启、版本回滚,这些都是裸进程方案给不了的。流媒体调试本身就是个多环节协作的活,尽量把环境层面的不确定性降到最低,才能把精力集中在真正重要的业务逻辑上。