本文梳理了理解RTMP协议的基本概念
访问我的博客了解更多
下图是播放器与 rtmp 服务端通信的例子
另外推荐阅读 nginx-rtmp-module 源码,比如,握手协议相关代码在 ngx_rtmp_handshake.c
文件
TCP 握手过程这里不详细展开,参考这篇文章 TCP 的那些事儿
RTMP 握手起到验证的作用,RTMP 握手方式主要分为:简单握手与复杂握手
Adobe 协议中描述的是简单握手,而 Adobe 产品 Flash Media Server 采用复杂握手的方式
与流程图有点不同,握手的实际流程分三个步骤:
我使用 Wireshark 抓包,验证了过程(我使用 nginx-rtmp-module 做服务器,ffmpeg推流,VLC Media Play播放)
报文的解释:
C0 与 S0
+-+-+-+-+-+-+-+-+
| version |
+-+-+-+-+-+-+-+-+
C1 与 S1
+-+-+-+-+-+-+-+-+-+-+
| time (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+
| zero (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+
| random bytes |
+-+-+-+-+-+-+-+-+-+-+
|random bytes(cont) |
| .... |
+-+-+-+-+-+-+-+-+-+-+
C2 与 S2
+-+-+-+-+-+-+-+-+-+-+
| time (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+
| time2(4 bytes) |
+-+-+-+-+-+-+-+-+-+-+
| random bytes |
+-+-+-+-+-+-+-+-+-+-+
|random bytes(cont) |
| .... |
+-+-+-+-+-+-+-+-+-+-+
RTMP 是用于网络传输的二进制协议,默认使用 Big-Endian 格式,因为 Big-Endian 格式在抓包时可读性较好
对于复杂握手,不使用 Adobe 产品 FMS 的话,简单了解即可
相对于简单握手,复杂握手增加了严格的验证,主要是 random 字段上进行更细化的划分
1528Bytes随机数的部分平均分成两部分,一部分764Bytes存储public key(公共密钥),另一部分764Bytes存储digest(密文,32字节)。
从二进制报文的角度,判断复杂握手的特征是,Version部分不为0,服务器端可根据这个来判断是否简单握手或复杂握手。
握手的了解到这里,下面继续看看握手之后的步骤
RTMP 有一个重要的概念:Application Instance,直观上,可以体现在 rtmp 的 url 上
我测试的推流例子,用到的 url 为: rtmp://192.168.23.152/live/movie
大家可以注意到,上面 wireshark 对 rtmp 抓包的截图中,握手后紧接一个 client->server 的报文 connect('live')
,
1909 36.398483095 192.168.23.152 192.168.23.152 RTMP 282 connect('live')
而这个 live
就是这次推流的 Application Instance
上面 wireshark 对 rtmp 抓包的截图中,有下面两行,第一行是 client->server,第二行是 server->client
1933 36.484940956 192.168.23.152 192.168.23.152 RTMP 105 Window Acknowledgement Size 5000000|createStream()
1935 36.485004644 192.168.23.152 192.168.23.152 RTMP 109 _result()
1946 36.528398367 192.168.23.152 192.168.23.152 RTMP 168 getStreamLength()|play('movie')|Set Buffer Length 1,3000ms
直观地,rtmp://192.168.23.152/live/movie 的 movie 是这次拉流的 stream
。
createStream 命令用于创建逻辑通道,该通道用于传输视频、音频、metadata。在服务器的响应报文 _result() 中会返回Stream ID,用于唯一的标示该Stream。
getStreamLength 命令用来获取 movie
的流的长度
Real Time Messaging Protocol (AMF0 Command getStreamLength())
RTMP Header
RTMP Body
String 'getStreamLength'
Number 3
Null
String 'movie'
Real Time Messaging Protocol (AMF0 Command play('movie'))
RTMP Header
RTMP Body
String 'play'
Number 4
Null
String 'movie'
Number -2000
根据 Adobe’s Real Time Messaging Protocol 里对 _result
命令的定义,上面 body 中第四个字段 “Number 1” 便是此次的 Stream ID
一般的 rtmp 连接的流程,都如上所示,后面便是命令与音视频数据的消息,比如:
根据 Adobe’s Real Time Messaging Protocol
NetStream sends the deleteStream command when the NetStream object is getting destroyed.
当 NetStream 对象销毁的时候发送删除流命令。
比如,播放器客户端停止播放,可以删除指定Stream ID的流。服务器不用对这条命令发送响应报文。