RTMP协议详解
一.总体介绍

RTMP协议是应⽤层协议,是要靠底层可靠的传输层协议(通常是TCP)来保证信息传输的可靠性的。在 基于传输层协议的链接建⽴完成后,RTMP协议也要客户端和服务器通过“握⼿”来建⽴基于传输层链接之 上的RTMP Connection链接,在Connection链接上会传输⼀些控制信息,如 SetChunkSize,SetACKWindowSize。其中CreateStream命令会创建⼀个Stream链接,⽤于传输具体的 ⾳视频数据和控制这些信息传输的命令信息。RTMP协议传输时会对数据做⾃⼰的格式化,这种格式的消 息我们称之为RTMP Message,⽽实际传输的时候为了更好地实现多路复⽤、分包和信息的公平性,发送 端会把Message划分为带有Message ID的Chunk,每个Chunk可能是⼀个单独的Message,也可能是 Message的⼀部分,在接受端会根据chunk中包含的data的⻓度,message id和message的⻓度把 chunk还原成完整的Message,从⽽实现信息的收发。
RTMP 是 Real Time Messaging Protocol( 实时消息传输协议) 的首字母缩写。该协议基于 TCP,是一个协议族,包括 RTMP 基本协议及 RTMPT/RTMPS/RTMPE 等多种变种。
RTMP 与 HTTP 一样, 都属于 TCP/IP 四层模型的应用层。
上述红色部分的含义如下图:

二. 握手
要建⽴⼀个有效的RTMP Connection链接,⾸先要“握⼿”:客户端要向服务器发送C0,C1,C2(按序)三个 chunk,服务器向客户端发送S0,S1,S2(按序)三个chunk,然后才能进⾏有效的信息传输。RTMP协议 本身并没有规定这6个Message的具体传输顺序,但RTMP协议的实现者需要保证这⼏点:
- 客户端要等收到S1之后才能发送C2
- 客户端要等收到S2之后才能发送其他信息(控制信息和真实⾳视频等数据)
- 服务端要等到收到C0之后发送S1
- 服务端必须等到收到C1之后才能发送S2
- 服务端必须等到收到C2之后才能发送其他信息(控制信息和真实⾳视频等数据)
如果每次发送⼀个握⼿chunk的话握⼿顺序会是这样:

理论上来讲只要满⾜以上条件,如何安排6个Message的顺序都是可以的,但实际实现中为了在保证握⼿ 的身份验证功能的基础上尽量减少通信的次数,⼀般的发送顺序是这样的,这⼀点可以通过wireshark抓 ffmpeg推流包进⾏验证:
|client|Server |
|----C0+C1---->|
|<----S0+S1+S2----|
|----C2---->|
2.1 C0和S0的格式

C0 和 S0 包都是一个单一的八位字节。
以下是 C0/S0 包中的字段˖
版本号(八位):在 C0 中,这一字段指示出客户端要求的 RTMP 版本号
在 S0 中,
这一字段指示出服务器选择的 RTMP 版本号
由于是8位,
最大值是二进制的 11111111
也就是能表示的值范围是 0-255.
当前版本的值是3。
0,1,2 是早期其他产品使用,是废弃值。
4-31是保留值,为了给未来实现版本使用。
32-255不允许使用。
对应代码
unsigned char cs0;占用1个字节,大小为0-255
2.2 C1 和 S1 的格式 - 1536个字节
Time (四个字节):这个字段段包含一个 timestamp,用于本终端发送的所有后续块的时间
起点。
这个值可以是0,或者一些任意值。
要同步多个块流,终端可以发送其他块流当前的timestamp的值。
Zero (四个字节):这个字段必须都是0
Random data (1528 个字节)
这个字段可以包含任意值。实际上是一些随机数,不需要对随机数进行加密保护,也不需要是动态的随机数。
该字段的作用的 区分 该响应死后自己发起的握手,还是对应的握手。
对应代码:

2.3 C2 和 S2 的格式
C2 和 S2 数据包长度都是 1536 字节。包含以下字段:
Time (四个字节): 这个字段必须包含终端在 S1 (给 C2) 或者 C1 (给 S2) 发的
timestamp。
Time2 (四个字节):这个字段必须包含终端先前发出数据包 (s1 或者 c1) timestamp。
Random echo (1528 个字节)。 这个字段必须包含终端发的 S1 (给 C2) 或者 S2 (给 C1)
的随机数 。
两端都可以一起使用 time 和 time2 字段再加上 timestamp 以快速估算带宽和/或者连接延迟,
但是不太可能有多大用处。

握手完成后,就可以发送数据了,那么这个数据的形式是什么样子的呢? 是 RTMP Chunk Stream,那么这个RMP dChunk Stream 具体是啥呢?
三. RTMP Chunk Stream (重点)
Chunk Stream是对传输RTMP Chunk的流的逻辑上的抽象,客户端和服务器之间有关RTMP的信息都在 这个流上通信。这个流上的操作也是我们关注RTMP协议的重点。
3.1 Message(消息)
这⾥的Message是指满⾜该协议格式的、可以切分成Chunk发送的消息,消息包含的字段如下:
- Timestamp(时间戳):消息的时间戳(但不⼀定是当前时间,后⾯会介绍),4个字节
- Length(⻓度):是指Message Payload(消息负载)即⾳视频等信息的数据的⻓度,3个字节
- TypeId(类型Id):消息的类型Id,1个字节
- Message Stream ID(消息的流ID):每个消息的唯⼀标识,划分成Chunk和还原Chunk为Message 的时候都是根据这个ID来辨识是否是同⼀个消息的Chunk的,4个字节,并且以⼩端格式存储 (Message Stream ID如何产⽣?audio和video使⽤不同的Message Stream ID)
3.2 Chunking(Message分块)
RTMP在收发数据的时候并不是以Message为单位的,⽽是把Message拆分成Chunk发送,⽽且必须 在⼀个Chunk发送完成之后才能开始发送下⼀个Chunk。每个Chunk中带有MessageID代表属于哪个 Message,接受端也会按照这个id来将chunk组装成Message。
为什么RTMP要将Message拆分成不同的Chunk呢?通过拆分,数据量较⼤的Message可以被拆分成 较⼩的“Message”,这样就可以避免优先级低的消息持续发送阻塞优先级⾼的数据,⽐如在视频的传输过 程中,会包括视频帧,⾳频帧和RTMP控制信息,如果持续发送⾳频数据或者控制数据的话可能就会造成 视频帧的阻塞,然后就会造成看视频时最烦⼈的卡顿现象。同时对于数据量较⼩的Message,可以通过对 Chunk Header的字段来压缩信息,从⽽减少信息的传输量。(具体的压缩⽅式会在后⾯介绍)
Chunk的默认⼤⼩是128字节,在传输过程中,通过⼀个叫做Set Chunk Size的控制信息(⻅ spec 5.4.1 )可以设置Chunk数据量的最⼤值,在发送端和接受端会各⾃维护⼀个Chunk Size(srs流媒 体服务器默认是60000),可以分别设置这个值来改变⾃⼰这⼀⽅发送的Chunk的最⼤⼤⼩。⼤⼀点的 Chunk减少了计算每个chunk的时间从⽽减少了CPU的占⽤率,但是它会占⽤更多的时间在发送上,尤其 是在低带宽的⽹络情况下,很可能会阻塞后⾯更重要信息的传输。⼩⼀点的Chunk可以减少这种阻塞问 题,但⼩的Chunk会引⼊过多额外的信息(Chunk中的Header),少量多次的传输也可能会造成发送的间 断导致不能充分利⽤⾼带宽的优势

最低0.47元/天 解锁文章
17万+

被折叠的 条评论
为什么被折叠?



