【流媒体】RTMP协议概述

最近一直在看流媒体中的RTMP协议,参考了多位前人的记录。考虑到RTMP协议内容比较多,同时也需要结合代码进行分析,所以会分成几个部分来记录,这里先记录RTMP实现的主要步骤

1.RTMP协议

RTMP(Real-Time Message Protocol)协议是由Adobe公司提出的一种专为实时音视频数据传输设计的专用网络协议,主要用于流媒体传输领域,如直播、在线视频播放等等。RTMP协议基于TCP,是一种有数据传输保障的协议,默认使用1935号端口,支持多种数据格式和传输方式,从而适用于不同的应用场景。RTMP能够应用于Windows、macOS、Linux、Android和iOS等不同的操作系统,进行高效的音视频数据传输。

熟悉RTMP协议,可以阅读官方的文档,这里我参考的是中文翻译:RTMP规范 adobe官网文档 中文版,版本是1.0(rtmp_specification_1.0.pdf)

RTMP协议是位于客户端和服务器之间的协议,并且是基于TCP协议的,在进行信息交互前,需要先进行几个步骤:
(1)client和server握手
(2)建立client和server之间通信信道(网络连接)
(3)建立client和server之间流通道(数据流连接)

1.1 握手(Handshake)

为了建立稳定的通信信道,RTMP基于TCP协议进行连接,而TCP协议是需要进行握手进行连接的,所以RTMP也需要进行握手连接。握手的流程图为
在这里插入图片描述

握手过程分为4个状态:
(1)Uninitialized(未初始化):
开始时,客户端和服务器都是 uninitialized (未初始化) 状态,会发送协议的版本号。客户端在数据包 C0 中将协议版本号发出。如果服务器支持这个版本,它将在回应中发送 S0 和 S1。如果不支持,服务器会才去适当的行为进行响应。在 RTMP 协议中,这个行为就是终止连接

(2)Version Sent (版本已发送):
随后,客户端和服务器都进入 Version Sent (版本已发送) 状态。客户端会等待接收数据包 S1 而服务器在等待 C1。一旦拿到期待的包,客户端会发送数据包 C2 而服务器发送数据包 S2。(客户端和服务器各自的)状态随即变为 Ack Sent (确认已发送)

(3)Ack Sent (确认已发送):
客户端和服务器分别等待 S2 和 C2

(4)Handshake Done (握手结束):
客户端和服务器可以开始交换消息了

1.1.1 C0和S0

C0和S0描述的是RTMP的版本号,长度为1字节。对于Client而言,发送的是C0,描述客户端要求的RTMP版本号;对于Server而言,发送的是S0,表示服务器选择的RTMP版本号。标准文档中规范的版本号为3,其中[0,2]这3个值是早期其他产品使用的,已被废弃;[4, 31]被保留为RTMP协议的未来版本使用;[32, 255]不允许使用。如果服务器收到的版本号无法被识别,则以版本3响应,收到这个响应的客户端可以将版本调整为3,或者放弃握手
在这里插入图片描述

1.1.2 C1和S1

C1和S1这两个字段通过校验时间戳来确认对端是否已经收到了发送过去的数据,这两个数据包可理解是反馈字段,长度为1536字节。其中字段的含义为:

(1)Time (4 Bytes)
该字段包含一个时间戳timestamp,用于本终端发送的所有后续块的时间起点。这个值可以是 0,或者一些任意值。要同步多个块流,终端可以发送其他块流当前的 timestamp 的值。

(2)Zero (4 Bytes)
该字段都是0

(3)Random data (1528 个字节)
该字段的值是随机生成的,终端需要区分出响应来自它发起的握手还是对端发起的握手,不需要对随机数进行加密保护,也不需要动态值
在这里插入图片描述

1.1.3 C2和S2

C2和S2的作用是告诉对方,我已经接收到你的反馈,现在可以进行后续操作了。其中,C2是S1的副本,S2是C1的副本,这两个数据包的长度都为1536个字节。下图中的几个字段分别的含义是:

(1)Time (4 Bytes)
该字段必须是对端发来的时间戳(对C2来说是S1的时间戳,对S2来说是C1的时间戳)

(2)Time2 (4 Bytes)
该字段必须是前面自己发送的C/S包里的时间戳

(3)Random echo (1528 Bytes)
该字段必须是对方发来的C1/S1包里携带的随机数据(对C2来说是S1,对S2来说是C1)。两端都可以一起使用 time 和 time2 字段再加当前 timestamp 以快速估算带宽和/或者连接延迟,但这不太可能是有多大用处
在这里插入图片描述

1.2 建立通信信道(NetConnection)

进行握手连接之后,可以建立通信信道(网络连接)来对接客户端和服务器,流程为:
在这里插入图片描述
(1)客户端发送命令消息 “connect” 到服务器端以请求对服务器端应用实例的连接

(2)收到 connect 命令后,服务器端发送协议消息 “Window Acknowledgement Size”(窗口确认大小) 到客户端。服务器端也会连接到 connect 命令中提到的应用

(3)服务器端发送协议消息 ‘Set Peer Bandwidth’ (设置对端带宽) 到客户端

(4)在处理完协议消息 ‘设置对端带宽’ 之后客户端发送协议消息 ‘窗口确认大小’ 到服务器端

(5)服务器端发送另一个用户控制消息 “StreamBegin”(流开始) 类型的协议消息到客户端

(6)服务器端发送结果命令消息告知客户端连接状态 “_result” (success/fail)

1.3 建立流通道(NetStream)

建立流通道时,根据数据流走向的不同,可以分成两种情况,第一种是client到server的流,第二种是server到client的流
(1)RTMP推流时的数据流连接
在这里插入图片描述
可以看到,在推流时,通过 “connect” 命令建立的流通道之后,client使用命令消息 “createStream” 建立流通道,server会反馈一个命令消息 “_result - createStream response” 来告诉client流通道建立是否成功
(2)RTMP拉流时的数据流连接
在这里插入图片描述
在建立流通道这一步骤上,拉流和推流的过程一致

1.4 播放(Play)

播放过程可以理解为是client拉流的过程,其主要步骤为:
(1)握手(Handshake)

(2)创建流(createStream),包括命令消息的发送(createStream)和接收(_result - createStream response)

(3)播放
 (a)client发送命令消息 “play”,表示我要播放你发送过来的视频,请把数据传输过来
 (b)server发送协议消息 “SetChunkSize”,表示我现在准备传输数据,先设置单个数据包chunk的大小
 (c)server发送用户控制消息 “StreamIsRecorded”,表示我现在传输过来的流是已录制好的
 (d)server发送用户控制消息 “StreamBegin”,表示我现在准备传输流,同时告诉client传输过去的流ID
 (e)如果client发送过来 “play” 消息中包括了 reset信息,server会发送命令消息 “onStatus-play reset”
 (f)server发送命令消息 “onStatus-play start”,表示网络流开始传输
 (g)server向client发送 “Audio Message” 和 “Video Message”
在这里插入图片描述

1.5 结束语

这里记录了RTMP协议的主要实现过程,包括握手(Handshake)、网络连接(NetConnection)、流连接(NetStream)和播放(Play)这几个步骤,其中对握手过程使用的数据包进行了详细的记录。但是,还有几个问题需要记录:
(1)对于其他步骤使用的命令格式(或消息格式)没有说明,例如 “Command Message”,"User Control"等
(2)这些命令(或消息)是按照何种方式在网络当中进行传输的
(3)在实际工程当中,这些过程是如何实现的

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值