RTMP

RTMP

RTMP,Real-Time Messaging Protocol 是由 Adobe 推出的音视频流传递协议,该协议从属于应用层,被设计用来在适合的传输协议(如 TCP)上复用和打包多媒体传输流(如音频、视频和互动内容)。RTMP 提供了一套全双工的可靠的多路复用消息服务,类似于 TCP 协议[RFC0793],用来在一对结点之间并行传输带时间戳的音频流,视频流,数据流。通常情况下,不同类型的消息会被分配不同的优先级,当网络传输能力受限时,优先级用来控制消息在网络底层的排队顺序。

RTMP 协议根据不同的套层,也可以分为:

  • 纯 RTMP: 直接通过 TCP 连接,端口为 1935
  • RTMPS: RTMP + TLS/SSL,用于安全性的交流。
  • RTMPE: RTMP + encryption。在 RTMP 原始协议上使用,Adobe 自身的加密方法
  • RTMPT: RTMP + HTTP。使用 HTTP 的方式来包裹 RTMP 流,这样能直接通过防火墙。不过,延迟性比较大。
  • RTMFP: RMPT + UDP。该协议常常用于 P2P 的场景中,针对延时有变态的要求。

在 Web 上可以通过 MSE(MediaSource Extensions)来接入 RTMP,基本思路是根据 WebSocket 直接建立长连接进行数据的交流和监听。

协议规范

RTMP 内部是借由 TCP 长连接协议传输相关数据,所以,它的延时性非常低。并且,该协议灵活性非常好(所以,也很复杂),它可以根据 message stream ID 传输数据,也可以根据 chunk stream ID 传递数据。两者都可以起到流的划分作用。流的内容也主要分为:视频,音频,相关协议包等。

RTMP 协议示范

当使用一个可靠的传输协议如 TCP[RFC0793] 时,RTMP 块流提供了一种可以在多个流中,基于时间戳的端到端交付所有消息的方法。RTMP 块流不提供任何优先级或类似形式的控制,但可以使用更高级别的协议来提供这样的优先级。例如,一个视频服务器可以根据发送的时间或确认每个消息的时间,来决定为一个网络差的用户丢弃视频信息,以确保音频信息的及时接收。RTMP 块流不仅包含了自己的协议控制信息,同时也提供了一个更高级别的协议机制,用来嵌入用户控制信息。

消息格式

消息格式可以被分割成多个块,用来在更高的协议中支持多路复用。在创建块消息格式时,应该包含以下字段:

  • 时间戳:消息的时间戳。这个字段占用 4 字节。

  • 长度:消息的有效长度。如果消息头不能被忽略,它应该包括长度。这个字段在块头中占用 3 字节。

  • 类型 ID:各种类型的协议控制消息的 ID。这些消息使用 RTMP 块流协议和更高级别的协议来传输信息。所有其他类型的 ID 可以用在高级协议,这对于 RTMP 块流来说,是不透明的。事实上,RTMP 块流中没有要求使用这些值作为类型;所有(无协议的)消息可能是相同的类型,或者应用程序使用这个字段来区分多个连接,而不是类型。这个字段在块头中占用 1 字节。

  • 消息流 ID:消息流 ID 可以是任意值。当同一个块流被复用到不同的消息流中时,可以通过消息流 ID 来区分它们。另外,对于 RTMP 块流而言,这是一个不透明值。该字段占用 4 字节,使用小端序。

握手

RTMP 连接从握手开始。它包含三个固定大小的块,不像其他的协议,是由头部大小可变的块组成的。客户端(初始化连接的一端)和服务端发送同样的三个块。为了方便描述,客户端发送的三个块命名为 C0,C1,C2;服务端发送的三个块命名为 S0,S1,S2。

客户端通过发送 C0 和 C1 消息来启动握手过程。客户端必须接收到 S1 消息,然后发送 C2 消息。客户端必须接收到 S2 消息,然后发送其他数据。服务端必须接收到 C0 或者 C1 消息,然后发送 S0 和 S1 消息。服务端必须接收到 C1 消息,然后发送 S2 消息。服务端必须接收到 C2 消息,然后发送其他数据。

+-------------+                           +-------------+
|    Client   |       TCP/IP Network      |    Server   |
+-------------+            |              +-------------+
      |                    |                     |
Uninitialized              |               Uninitialized
      |          C0        |                     |
      |------------------->|         C0          |
      |                    |-------------------->|
      |          C1        |                     |
      |------------------->|         S0          |
      |                    |<--------------------|
      |                    |         S1          |
 Version sent              |<--------------------|
      |          S0        |                     |
      |<-------------------|                     |
      |          S1        |                     |
      |<-------------------|                Version sent
      |                    |         C1          |
      |                    |-------------------->|
      |          C2        |                     |
      |------------------->|         S2          |
      |                    |<--------------------|
   Ack sent                |                  Ack Sent
      |          S2        |                     |
      |<-------------------|                     |
      |                    |         C2          |
      |                    |-------------------->|
 Handshake Done            |               Handshake Done
      |                    |                     |

下面是握手示意图中提到的状态:

  • 未初始化:协议版本号在此阶段发送。客户端和服务器均处于未初始化状态。客户端发送携带协议版本号的 C0 包。如果服务器支持此版本,回复 S0 和 S1 包。如果服务器不支持此版本,使用适当的动作回复。在 RTMP 协议中,此动作是中止连接。 注: 在”C0 和 S0 格式”章节中提及,如果服务器不支持客户端的版本号,可以选择降到版本 3 或中止。

  • 发送版本:客户端和服务器双方在未初始化状态后,会进入发送版本状态。之后,客户端等待 S1 包,服务器等待 C1 包。待接收到数据包,客户端发送 C2 包,服务器发送 S2 包。然后,双方都进入答复状态。客户端等待 C2 的答复,服务器等待 S2 的答复。

  • 握手完成:客户端和服务器交换消息。

RTMP 代理

关于 RTMP 代理的协议规范。RTMP 是字节协议,第一个包是 c0,1 个字节,一般是 03 表示是明文的 RTMP。所以如果需要做 RTMP 代理,如果直接转发 RTMP 客户端的消息,是没法传递额外的信息的,譬如 HTTP 代理在 Header 中传递的 X-Real-IP,即客户端的 IP,就没法给 RTMP 的后端了。

因此,RTMP 的 Proxy 协议必须使用私有协议,c0 的意义必须改写了,譬如另外一个值表示是代理,后面跟随了一些协议信息,这个协议就是 RTMP Proxy 协议。

使用网络字节序,big-endian。在 C0 前插入代理的包,兼容 RTMP 标准协议。

标准 RTMP 协议如下:

C0,     1B, 03表示明文RTMP。后面是C1C2以及其他消息。

RTMP 代理协议如下:

F3,         1B,常量0xF3,表示RTMP代理协议。
Size,       2B, 表示代理数据的长度,即Size和C0之间的数据。
X-Real-IP,  4B, 表示客户端的真实IP。
C0,         1B,原始客户端的C0,方便代理直接转发客户端的数据。

备注:一般 Size 应该不超过 C0C1 长度,即Size<=1537

例如,标准 RTMP 客户端的消息:

03            // 客户端的C0包,后面是C1C2,以及其他的消息。

或者,代理客户端发送的消息:

F3            // 表示是RTMP代理
00 04         // 表示Extra有4字节
C0 A8 01 67   // 表示客户端IP,C0.A8.01.67,即192.168.1.103
03            // 客户端原始的C0数据。从这个数据(包括它本身)开始,就是客户端发送的消息了,譬如C1C2。

RTMP 协议,譬如握手的 C0、C1、C2、S0、S1、S2,以及数据部分,都没有变更。

上一页
下一页