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。

客户端通过发送C0C1消息来启动握手过程。客户端必须接收到S1消息,然后发送C2消息。客户端必须接收到S2消息,然后发送其他数据。服务端必须接收到C0或者C1消息,然后发送S0S1消息。服务端必须接收到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包。如果服务器支持此版本,回复S0S1包。如果服务器不支持此版本,使用适当的动作回复。在RTMP协议中,此动作是中止连接。 注:在”C0S0格式”章节中提及,如果服务器不支持客户端的版本号,可以选择降到版本3或中止。

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

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

RTMP代理

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

因此,RTMPProxy协议必须使用私有协议,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,以及数据部分,都没有变更。

上一页
下一页