news 2026/9/16 5:02:39

RTMP协议全解析:为何仍是直播推流事实标准与实战搭建

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RTMP协议全解析:为何仍是直播推流事实标准与实战搭建

Flash Player在2020年底正式停止维护,很多人以为Flash生态里的那些技术也一起进了坟墓。但有个例外一直活得好好的,就是今天要聊的RTMP(Real Time Messaging Protocol,实时消息传输协议)。不信你去看看直播行业后端是怎么把画面推到CDN的,或者翻翻各大云厂商直播服务的接入文档,RTMP仍然是出场率最高的推流协议。它确实是上世纪的东西,但直到今天,做直播开发、流媒体运维、甚至是用OBS自己开播的人,都躲不开它。

这篇文章我会把RTMP讲透:它到底解决了什么问题,为什么Flash没了它还在,消息是怎么在TCP连接上流动的,然后带你把一套推拉流环境从零搭起来,最后聊聊什么场景下该选它、什么场景下该换别的协议。想学视频开发或者搞直播业务的,看完这篇应该能直接上手干活了。

1. Flash早就死了,RTMP为什么还活着

1.1 RTMP的诞生与Flash时代

RTMP是Macromedia在2002年前后搞出来的私有协议,后来Adobe把Macromedia收了,协议就成了Adobe家的东西。当时它的定位非常清晰:给Flash Player和Flash Media Server之间传输音视频数据用。你回忆一下当年网页上看视频、玩Flash小游戏的体验,那些视频用的底层传输协议大部分就是RTMP。

它的设计目标在当年很超前:一是低延迟,数据到了就推,不用等一个文件攒完整;二是支持双向交互,客户端可以给服务器发命令,服务器也能回推消息;三是基于TCP的可靠传输,不乱序、不丢包。这些特性放到今天的互动直播场景里依然不过时。

1.2 Flash凉了,推流侧的RTMP没凉

Flash Player都停了,RTMP为什么没跟着死?原因其实不复杂:它在"推流"这个环节已经形成了事实标准

用一句话说清楚推流和拉流的区别:推流是主播端把画面声音送进服务器,拉流是观众端从服务器取画面声音。Flash的死影响的是浏览器端拉流播放,RTMP不再被浏览器原生支持,所以拉流侧现在普遍换成了HLS或者HTTP-FLV。但推流侧的生态早就被RTMP占据了,这个惯性实在太大:

  • OBS等主流的直播推流软件,默认的输出协议就是RTMP
  • 市面上几乎所有的专业编码器、无人机图传、运动相机,固件里都内置了RTMP推流功能
  • 各大云厂商的直播服务接流节点统一支持RTMP,接入成本极低
  • 无数存量系统、文档、SDK都是围绕RTMP推流设计的

这就形成了一个很微妙的局面:浏览器端的播放早已抛弃RTMP,但所有"把画面送进互联网"的操作,都还在用这个"老古董"协议。

1.3 "推流"这个环节为什么绕不开RTMP

你可能会问:推流侧的技术也都更新换代了,凭什么大家还是用RTMP?我的理解是:推流这个动作对通用性的要求远高于对先进性的要求。

推流端不只是"运行在用户电脑上的软件",还可能是摄像头、无人机、工业设备、嵌入式开发板(比如ESP32-CAM这类小设备)。这些设备的算力有限,不可能内置太复杂的协议栈。RTMP基于TCP,可靠、稳定、CPU开销小,对比现在很火的WebRTC那一大套ICE/SRTP/DTLS流程,RTMP的实现就简单太多了。对于硬件厂商来说,烧一个RTMP推流库进固件,成本低、兼容性好,没有理由改。

对CDN和云厂商来说也是这样,接流节点需要接纳各种推流端,用一个大家都支持的协议做"最大公约数",能省掉海量的兼容性问题。所以你现在看到的直播链路,绝大多数依然是这条:摄像头/软件推流端 → RTMP推流 → 云端接入 → 转封装分发(HLS/HTTP-FLV/WebRTC) → 观众播放。RTMP虽然只管了第一段路,但这一段路恰恰是绕不开的。

2. RTMP的握手、命令与消息块:低延迟的秘密

2.1 从一次完整的RTMP连接说起

RTMP基于TCP,默认端口是1935,也支持封装在HTTP里的RTMPT(端口80)和带TLS加密的RTMPS(端口443)。看协议序号就明白了:连接层用TCP保证可靠传输,协议层自己定义了握手、命令和数据格式。

一次完整的RTMP推流连接可以拆成几大步:

  1. TCP三次握手,建立底层连接
  2. RTMP握手:客户端发C0+C1,服务器回S0+S1+S2,客户端再发C2,确认双方协议版本和随机数据。握手包里有时间戳和随机字节,主要目的是确认双方都按照RTMP协议工作
  3. connect命令:客户端发一个AMF格式的connect命令,参数包括app名称、tcUrl(就是完整的推流地址)等,请求连到某个应用上
  4. createStream命令:连接成功后,客户端再发createStream命令,创建一个用于传输音视频的Stream
  5. 推流或播放:推流端发publish命令,播放端发play命令,然后就进入音视频数据的正常传输阶段
  6. 音视频数据传输:视频帧和音频帧被打成Message,再拆成Chunk流持续发送

我之前第一次抓RTMP包的时候,最大的感受是:这个协议聊天的频次非常密集。每次推流建连,光是命令消息就有好几个往返,不像现在很多协议一个HTTP请求就完事了。但要理解,RTMP设计了这些步骤是为了支持复杂的交互和状态管理,而且这些命令在长连接里只发生一次,后续传输成本就非常低了。

2.2 消息块(Chunk)设计:头压缩与多流复用

RTMP的数据传输单位是Message,可以简单理解成一个"逻辑数据包",里面装着音频帧、视频帧或者命令数据。但这些Message真正在网络上发送时,会被切成比较小的Chunk(块)。为什么要切?

因为RTMP是长连接,一条TCP连接上可能同时跑着音频流、视频流、控制命令流,Chunk机制允许这些不同类型的Message交错发送,避免一个大视频帧把网络堵住,让其他数据干等。TP层提供的字节流没有天然的"报文边界",所以每个Chunk都会带上一个Basic Header,用于标识这个Chunk属于哪个Chunk Stream ID,接收端根据ID把碎片重组回Message。你可以想象成快递仓库里,不同订单的商品放在同一个传送带上,每个快件上贴着订单号,到了目的地再分拣归类。

RTMP还有一个细节特别有意思,就是变长Chunk头(Chunk Header)。默认的Chunk size是128字节,但连接双方可以通过Set Chunk Size消息协商,把块大小调大。我实测下来,推流时把chunk_size配置到4096或更大,大分辨率视频帧的传输效率会有明显提升,CPU占用也低一些。这个优化在nginx-rtmp的配置里一行就能搞定,后面实操环节会提到。

2.3 命令消息与AMF格式

RTMP的命令消息用的是AMF(Action Message Format)来序列化。AMF是Adobe定义的一套二进制序列化格式,功能上类似现在的JSON,能表达数字、字符串、对象、数组等类型,但编码方式是二进制的,比JSON紧凑。RTMP的命令消息类型号是20,数据消息是18。

拿connect命令举个例子,消息体里会有:

  • 命令名:"connect"
  • 事务ID(Transaction ID):用来把请求和响应配对
  • 命令对象:一堆键值对,包含app(应用名,比如"live")、type、flashVer、tcUrl等

打开Wireshark去看RTMP的抓包,你会发现这些字段一目了然。AMF其实是很老的格式了,但胜在稳定,被Flash整个生态大量使用,所以RTMP一直沿用了下来。推流中常见的publish命令、play命令、deleteStream命令,都是通过AMF格式拼装传输的。

2.4 RTMP低延迟的真相

聊RTMP必然绕不开延迟问题。RTMP把延迟控制在2到5秒这个量级,核心原因是它没有"切片"这个动作。对比一下HLS:HLS会把直播流切成一段一段的TS文件,每段通常2到6秒,播放器要下载完一个切片才能播,切片+下载+播放器缓冲叠起来,延迟轻松到6秒以上,配置不好甚至30秒。而RTMP是长连接直接推流,服务器收到数据后可以立刻转发给播放端,中间没有等切片的时间。

同时,服务器通常还会配合GOP Cache(关键帧缓存)机制。新观众进入直播间时,如果直接播当前帧,画面会花屏,因为解码依赖前面的I帧。服务器缓存一个GOP(从I帧开始的一组画面),新观众进来时把缓存的数据先发过去,播放器就能从关键帧开始正常解码。nginx-rtmp里开这个功能就是一行配置,但很多新手会漏掉,导致拉流黑屏或者花屏。

3. 从零搭一套RTMP推拉流环境:nginx-rtmp、ffmpeg与OBS实测

理论讲再多,不如亲手跑通一条链路。这一节我带你在本地把RTMP服务器、推流端、播放端全部跑起来。整个过程只需要一台Linux机器(虚拟机也OK)、一个ffmpeg、一个播放器,不需要额外花钱。

3.1 准备环境与安装nginx-rtmp

最简单的方式是用nginx的官方rtmp模块包。以Ubuntu/Debian为例:

sudo apt update sudo apt install libnginx-mod-rtmp ffmpeg ffplay

装完检查一下模块是否加载了:

nginx -V 2>&1 | grep rtmp # 输出结果里能看到 --add-module=../nginx-rtmp-module 之类的字样就说明OK

如果系统源里没有这个模块包,那就走编译安装路线。编译的时候记得装好依赖包build-essential、libpcre3-dev、libssl-dev、zlib1g-dev,然后按标准流程操作即可:

wget http://nginx.org/download/nginx-1.24.0.tar.gz git clone https://github.com/arut/nginx-rtmp-module.git tar -zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0 ./configure --add-module=../nginx-rtmp-module --with-http_ssl_module make && sudo make install

编译安装后,nginx默认在/usr/local/nginx下,启动方式为sudo /usr/local/nginx/sbin/nginx,注意不要和系统自带的nginx冲突。

3.2 踩坑点:nginx.conf里最容易配错的三个细节

网上配RTMP服务器的教程很多,但我发现新手特别容易在nginx.conf上翻车,主要栽在三个地方。

第一,rtmp配置块写错了位置。rtmp块必须和http块平级,不能塞在http块里面。正确的位置是在http块外面,单独一层:

worker_processes auto; events { worker_connections 1024; } http { # HTTP 配置保持默认即可 } rtmp { server { listen 1935; chunk_size 4096; application live { live on; record off; gop_cache on; } } }

第二,防火墙忘了放行1935端口。RTMP默认走1935/TCP,装好服务后要在防火墙里放行,不然从外部推流一定会失败。命令参考:

# UFW 防火墙 sudo ufw allow 1935/tcp # firewalld sudo firewall-cmd --add-port=1935/tcp --permanent sudo firewall-cmd --reload

第三,没有配置chunk_size和gop_cache。chunk_size默认是4096也行,但如果你的视频码率很高,可以调大。gop_cache我强烈建议打开,不然后面拉流测试大概率看到黑屏。配置完成后先测试语法再重启:

nginx -t sudo systemctl reload nginx # 或者 sudo nginx -s reload

验证服务器起来了没:

ss -tlnp | grep 1935 # 看到 LISTEN 状态就说明RTMP服务已经在线

3.3 用ffmpeg推流:参数背后的含义

有了服务器,推流这个动作其实就是一个ffmpeg命令的事。先拿一个本地视频文件推流测试:

ffmpeg -re -i /path/to/video.mp4 -c copy -f flv rtmp://127.0.0.1/live/test

这里有两个参数值得展开说。-re是让ffmpeg按原视频的帧率速度读取文件,不是极速读完,而是模拟直播时的实时推送节奏,没有它会瞬间把整个视频推完,测试就失去了意义。

-c copy是流复制,直接拷贝文件的音视频编码数据,不做转码,CPU占用极低,适合网络和链路测试。如果是从摄像头采集推流,就要转码了,命令变成:

ffmpeg -f v4l2 -framerate 30 -video_size 1280x720 -i /dev/video0 \ -c:v libx264 -preset veryfast -tune zerolatency \ -c:a aac -f flv rtmp://127.0.0.1/live/test

注意Linux下摄像头设备是/dev/video0,macOS上类似的是"0:0"这种设备标识。编码参数方面,preset veryfast走速度路线,tune zerolatency是针对低延迟场景优化,这两个参数在直播推流里几乎是标配。

推流开始后,控制台会滚动输出帧率、码率、时间戳这些信息。看到frame和fps稳定增长,说明推流基本没问题了。

3.4 用ffplay和OBS验证整条链路

拉流测试用ffplay一行命令就能搞定:

ffplay rtmp://127.0.0.1/live/test

弹出窗口看到画面、听到声音,全链路就通了。这时候再用ffprobe看一眼流信息会更放心:

ffprobe rtmp://127.0.0.1/live/test # 输出里能看到视频编码、分辨率、音频采样率等信息

用OBS走一遍推流也很方便,适合模拟真实主播端的配置。在OBS设置里选择"自定义流媒体服务器",服务器地址填rtmp://你的IP/live,串流密钥填一个自定义的流名(比如test),点开始推流即可。关键是要把IP换成实际地址,注意OBS推流一般不用加完整的流路径,因为OBS会把密钥自动拼接上去。

调试过程中如果遇到问题,可以参考这张排查表:

现象可能原因解决办法
握手超时、连接拒绝防火墙未放行1935放行端口,检查监听状态
推流端连接被拒nginx rtmp配置错误nginx -t 检查配置,重启服务
播放端黑屏/花屏gop_cache未开启rtmp application里设置gop_cache on
音画不同步推流端时间戳问题检查原文件时间戳,或统一编码器时间基准
推流画面卡顿上传带宽不够降低码率,检查网络

4. 网上流传的RTMP测试地址,能测出什么,又测不出什么

4.1 为什么大家都搜"RTMP测试地址"

搜索引擎里"rtmp测试地址"这个关键词热度一直很高,我太能理解这种需求了。做流媒体开发或者直播运维的人,经常会遇到一个尴尬场景:要验证播放器SDK、测试解码器、确认网络环境到某些公网节点通不通,手头却没有一个稳定的直播流。从零搭一个本地推流环境当然最好,但很多情况下你没有服务器权限,或者只是临时验证一下播放端的兼容性,这时候公共测试地址就是最快的选择。

网上流传比较广的一个测试地址是rtmp://camlive.iqilu.com/live/streamdelivery1,这是某个省级媒体平台开放出来的公共直播流,被各大技术社区当作RTMP联调测试用。类似的公共流其实有不少,但很多都因为服务器下线或访问控制策略变更而失效了,能稳定存活的不多。

4.2 用公共测试地址做连通性验证

拿到测试地址后,第一件事是验证它是否还活着。用ffprobe做一次"检查流信息"的操作最直接:

ffprobe rtmp://camlive.iqilu.com/live/streamdelivery1

如果输出里能看到Stream #0:0和Stream #0:1这样的音视频流信息,说明这个地址还能用。如果卡在连接阶段或者报错Timeout/Handshake failed,那就要换一个测试地址了。

确认流存活后,再去验证播放端。ffplay直接拉流试播:

ffplay rtmp://camlive.iqilu.com/live/streamdelivery1

播放器弹出窗口、画面正常渲染,说明你的网络出口到该CDN节点的链路是通的,RTMP握手、流交互、音视频解码流程全部正常。如果你在做播放器SDK的兼容性测试,这就是一个很好的回归验证环境。

4.3 公共测试地址的局限

但这类公共地址的局限也很明显,我建议你别对它期望太高。

它只能测拉流,不能测推流。公共流是媒体平台推给所有人的,你没有权限往这个地址推数据,所以推流测试必须自己搭服务器。

它不稳定,随时可能失效。公共流是媒体平台顺带开放的,不是专门为开发者准备的测试服务。人家调整线路、改编码、下架节目,你的测试环境就跟着挂了。我见过不少人把公共地址写死在项目配置里,结果某天线上播放器全部连不上,排查半天才发现是公共测试地址失效了。

它测不了延迟和弱网场景。公共流的服务器距离不可控,你测出的延迟值没有参考意义。真要测自己的播放器指标,还是得用自己的源。

所以我的建议是:公共测试地址用于"临时冒烟验证"可以,但凡是正经的开发调试,老老实实搭一套本地nginx-rtmp环境,成本低、可控性强、能复现问题,这才是正道。我自己在团队里就要求所有客户端开发必须用本地环境做联调,公共地址只允许在给外部演示的时候用一下。

5. RTMP的短板和它的替代者们

5.1 RTMP真正的短板在哪里

不管你多喜欢RTMP,它的短板是客观存在的。第一个也是最大的问题:基于TCP,弱网表现差。TCP的拥塞控制和丢包重传机制在弱网环境下会导致延迟急剧升高,甚至卡顿。手机网络不稳的时候,RTMP推流经常出现断断续续的情况,就是这个原因。相比之下,基于UDP的SRT和WebRTC在抗丢包方面要灵活得多。

第二个问题是播放端兼容性差。浏览器已经不支持RTMP原生播放了,你需要把流转成HTTP-FLV(配合flv.js)或者HLS才能在网页上看。移动端App倒是可以用原生RTMP播放,但也不是所有播放器都内置了RTMP解码器,集成成本不低。

第三个问题是默认不带加密。RTMP是明文协议,RTMPS相当于加了TLS的RTMP,但不是所有服务器和客户端都支持。做直播特别是付费直播时,链路加密是刚需,RTMPS能覆盖一部分场景,但生态不如标准的HTTPS拉流那么无缝。

还有一个小坑:1935端口在很多企业内网和校园网络里被防火墙策略挡着,遇到这种情况想走RTMP就得用RTMPT(封装在80端口)绕行,但RTMPT的性能损耗比较明显,也不是长久之计。

5.2 主流替代协议对照

这些年在直播分发侧,HLS和HTTP-FLV已经占据了主流位置;在超低延迟场景,WebRTC异军突起;在弱网传输场景,SRT表现亮眼。它们的核心差异可以用一张表说清楚:

协议传输层延迟浏览器兼容适用场景
RTMPTCP2-5秒推流建链、低延迟拉流(需转封装)
HTTP-FLVTCP/HTTP2-5秒好(flv.js)Web端低延迟直播播放
HLSHTTP6-30秒原生支持大规模点播/直播、兼容性优先
WebRTCUDP<1秒原生支持互动连麦、实时音视频会议
SRTUDP与RTMP相近一般跨国传输、弱网环境、公网矩阵

注意几个容易理解的"为什么":HLS延迟高是因为切片和文件下载的机制决定的,但它的好处是可以通过普通HTTP静态文件服务分发,天然过CDN、天然支持缓存,手机浏览器和系统播放器都能直接播,大规模直播场景优势巨大。WebRTC走UDP,能实现秒开和毫秒级互动,但它要求公网协商ICE通道,架设和维护的复杂度比RTMP高一个量级,目前主要用在连麦和会议场景。

5.3 我的选型建议

具体到不同场景,我通常的建议是:

推流侧:继续用RTMP,没有之一。除非你在做纯Web端的互动直播(那直接用WebRTC推流),否则RTMP推流的稳定性和兼容性依然是最好的选择。国内云厂商直播产品的标准接入方式也都保留了RTMP。

拉流侧:优先根据播放端选择。Web端追求低延迟用HTTP-FLV+flv.js,追求兼容性用HLS;App端直接用RTMP协议或者转成HLS都行;如果做的是互动连麦级别的低延迟,只有WebRTC能接得住。

弱网传输:往SRT方向考虑。这协议在公网跨地区传输、4G/5G弱网环境下比RTMP抗造得多,很多硬件厂商和实验性项目已经在用SRT做推流了。但生态成熟度和接入便捷性目前还不如RTMP。

**我个人的体会是,**选协议永远不是要找一个"最好的",而是要找一个"当前场景最省事、长期最稳定"的。RTMP不先进,也不优雅,但它足够成熟、足够通用,在推流端依然是事实标准。与其天天纠结要不要换新协议,不如先把RTMP链路玩明白——你懂了TCP长连接、懂了Chunk流、懂了AMF命令,回头再去学WebRTC或者SRT,会发现很多底层思路是相通的,学习成本低一大截。

最后再分享一个小技巧:抓RTMP包调试的时候,可以在Wireshark里打开Analysis->Decode As,协议选RTMP,Wireshark会把消息类型、事务ID、AMF命令全部解析成可读形式。我第一次用这招定位推流失败问题时,不到十分钟就从抓包里看出了是app名称不匹配导致的连接被拒。做流媒体调试,学会看抓包有时候比看日志效率高得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 5:00:32

双层优化:机器学习与视觉任务中的统一决策框架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 4:59:53

基于霍尔摇杆与偏心马达的双轴触觉反馈摇杆系统设计

做了这么多年人机交互相关的项目&#xff0c;我一直对“手感”这两个字特别较真。摇杆这东西&#xff0c;看起来简单&#xff0c;不就是两个电位器或者霍尔元件返回个电压嘛&#xff0c;但真正要做到“精准”和“有感知”&#xff0c;里面的门道比想象中多得多。前阵子我基于 T…

作者头像 李华
网站建设 2026/9/16 4:59:07

EEGNet复现全链路指南:从信号预处理到工业部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 4:59:06

Java+Vue+Spring Boot校园快递代取系统全栈开发实战

前阵子整理项目仓库的时候&#xff0c;翻出了当时做的这个校园快递代取系统&#xff0c;Java Vue Spring Boot这套组合&#xff0c;前前后后折腾了差不多三个月&#xff0c;从需求梳理、数据库设计到前后端联调&#xff0c;踩坑无数但也收获很大。当时做这个项目的初衷特别朴…

作者头像 李华
网站建设 2026/9/16 4:59:02

类型驱动开发:让类型约束成为行为导向的编程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华