RTMP 协议解析 1
介绍
📖 什么是 RTMP?
RTMP协议(Real-Time Messaging Protocol,实时消息传输协议)是由Adobe公司(最初由Macromedia开发)设计的一种用于实时传输音频、视频和数据流的网络协议,主要用于直播和流媒体传输,最初是为了让 Flash Player 和 Flash Media Server 之间进行音视频和数据的实时传输。
现在虽然 Flash 被淘汰了,但 RTMP 这个协议因为其简单、低延迟、稳定的特点,依然在直播领域广泛应用,比如 OBS 推流、斗鱼、Bilibili、Twitch 都在用。
• 作用:RTMP用来实现音视频数据的实时传输,比如直播视频、在线音频等。它让客户端(如播放器)和服务器之间能快速、连续地交换多媒体数据。
• 工作层级:RTMP是应用层协议,依赖底层的传输层协议(通常是TCP)来保证数据可靠传输。
• 默认端口:通常使用TCP的1935端口进行通信,也有变种支持通过HTTP端口(80、443)传输以穿透防火墙。
• 多路复用和分包:RTMP会把数据分成许多小块(称为Chunk),每个Chunk带有标识信息,接收端再把这些Chunk组装成完整的消息,实现多路复用和高效传输。
• 双向通信:客户端和服务器之间可以相互发送命令和数据,比如客户端发出“播放”、“暂停”命令,服务器则推送视频流。
RTMP 播放,浏览器端已经不支持(需要 Flash,已经淘汰)。
🛠️ RTMP 的核心特点
特点 | 说明 |
---|---|
低延迟 | 通常能做到 1-2 秒,非常适合直播 |
分块传输 | 大文件(比如视频流)会被切成小块,实时传输 |
支持音视频同步 | 可以同时传输音频、视频、文字数据,保持同步 |
基于 TCP | 传输可靠,不会丢包,但速度比 UDP 稍慢一点 |
持久连接 | 建立一次连接后长时间保活,适合流式数据 |
📦 RTMP 的数据流程
RTMP 整个通信过程可以分为三步:
- Handshake(握手阶段)
- 建立 TCP 连接后,客户端和服务器通过握手确认彼此协议版本,完成初始化。
- Connect(连接阶段)
- 客户端发送一个 connect 命令,请求推流或拉流,比如指定应用名(app)、流名(streamName)、认证信息(token)等。
- Stream(数据传输阶段)
- 开始音视频数据传输,比如推送 h264 编码的视频流、AAC 编码的音频流,还有一些控制消息(比如 pause、seek、metadata 更新)。
🔥 常见的 RTMP 使用场景
场景 | 示例 |
---|---|
直播推流 | OBS 推流到斗鱼、虎牙、B站 |
直播拉流 | 播放器从服务器拉 RTMP 流 |
流媒体服务器内部通信 | Nginx-RTMP、SRS、Red5、Wowza 等服务器使用 |
实时弹幕推送 | 用 RTMP 的 data message 功能 |
📡 RTMP URL 的格式
rtmp://服务器地址:端口号/app/stream
🔍 RTMP 的几个子协议
协议 | 说明 |
---|---|
RTMPT | 把 RTMP 封装成 HTTP 请求(端口80,穿防火墙) |
RTMPS | 加密版 RTMP,用 SSL/TLS |
RTMPE | Adobe 自己的加密版 RTMP,半开源 |
⚡ 现在最流行的一种组合是:
- 推流用 RTMP(客户端推到服务器)
- 播放用 HLS 或 WebRTC(服务器转码输出给观众 HTTP-FLV)
软件播放
这里主要针对mac 平台的播放软件:
-
VLC Media Player
-
Live Stream Player
提供两个可以测试的 rtmp 流地址
rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid
rtmp://ns8.indexforce.com/home/mystream
📦 (标准直播系统):
主播 → RTMP 推流 → 直播服务器(比如 SRS) → 转码 + 分发 → → HTTP-FLV/HLS(观众拉流,单向)→ WebSocket(观众互动消息,双向)→ WebRTC(连麦,双向音视频)
流程链路
1. 🔥 建立 TCP 连接
首先,RTMP 是基于 TCP 的,所以:
- 客户端(比如 OBS、推流SDK)通过 TCP 连接到 RTMP 服务器(比如 SRS、Nginx-RTMP、Wowza)。
- 默认端口是 1935(可以改成443/80穿透)。
Client → TCP三次握手 → Server
2. 🔥 RTMP 握手(Handshake)
RTMP的握手分成3步(C0、C1、C2 + S0、S1、S2):
阶段 | 描述 |
---|---|
C0 + C1 | 客户端发送 1 字节版本号(C0) + 1536字节随机数据(C1) |
S0 + S1 + S2 | 服务器返回 1字节版本号(S0)+1536字节随机数据(S1),再返回一份确认(S2) |
C2 | 客户端最后发送一份确认 |
3. 🔥 连接请求(Connect)
握手成功后,客户端发送一个 connect 命令,告诉服务器:
- 我要连哪个应用(app,比如 /live)
- 使用什么流(stream key,比如 /live/stream123)
- 包含了很多信息(版本号、URL、认证token、编码格式要求等等)
服务器收到 connect 请求后,回复一个 _result 或 _error。
4. 🔥 建立流(CreateStream)
- 客户端再发 createStream 请求(可以理解成 “我要打开一个播放或推流通道”)
- 服务器返回一个 stream_id
- 这个 stream_id 后续用来标识当前的媒体流。
5. 🔥 推流或拉流(Publish / Play)
类型 | 动作 |
---|---|
推流(主播) | 发送 publish 命令(准备往服务器推送音视频) |
拉流(观众) | 发送 play 命令(准备从服务器拉取音视频) |
6. 🔥 音视频数据传输
这部分就是不停发 RTMP Message:
- 音频帧(Audio Message)
- 视频帧(Video Message)
- 元数据(Metadata Message,比如宽高fps变化)
每个消息有自己的 header 和 payload,服务器和客户端之间基于 TCP 保持通信
📦 连接和释放的关系
🔥 连接建立流程(Connection Setup)
TCP连接 → RTMP握手 → connect命令 → createStream → publish或play → 推流或拉流
整个连接生命周期是绑定的!
- 只要 TCP 连接存在,RTMP的 session 就存在。
- 流(stream)是基于连接之上的一个资源(stream_id标识)。
🔥 连接释放流程(Connection Teardown)
场景 | 触发条件 |
---|---|
正常断开 | 客户端发送 deleteStream 命令,告诉服务器我要关闭流;然后发送 close 命令断开连接;最后 TCP 四次挥手 |
异常断开 | 客户端断电、崩溃、网络异常,TCP连接直接断掉 |
服务器踢出 | 如果服务器检测到非法流、长时间空闲、认证失败,会强制关闭 TCP 连接 |
超时断开 | 有些服务器设置 idle timeout,比如 60秒无数据,自动踢掉 |
一旦 TCP 断开,RTMP session 和所有相关 stream 都被清理。
如下图所示:
[Client] [Server]| TCP connect ||------------------->|| RTMP handshake ||<------------------->|| connect ||------------------->|| _result ||<-------------------|| createStream ||------------------->|| _result(streamId)||<-------------------|| publish/play ||------------------->|| start streaming ||<===================>|| deleteStream ||------------------->|| close connection ||------------------->|| (TCP close) |