一文搞懂 RTMP直播流媒体协议

前言

本文主要讲解 RTMP 协议,并通过 wireshark 对 RTMP 进行抓包并分析具体过程。

一、RTMP 简介

1、RTMP 介绍

RTMP 是 Real Time Messaging Protocol( 实时消息传输协议) 的首字母缩写。该协议基于 TCP,是一个协议族,包括 RTMP 基本协议及 RTMPT/RTMPS/RTMPE 等多种变种。

RTMP 与 HTTP 一样, 都属于 TCP/IP 四层模型的应用层。

RTMP 协议传输时会对数据格式化,而实际传输的时候为了更好地实现多路复用、分包和信息的公平性,发送端会把 Message 划分为带有 Message ID 的 Chunk,每个 Chunk 可能是一个单独的 Message,也可能是 Message 的一部分,在接收端会根据 Chunk 中包含的 data 的长度,message id 和 message 的长度把 chunk 还原成完整的 Message,从而实现信息的收发。 (Message, Chunk)

2、变种

它有多种变种:

RTMP 工作在 TCP 之上,默认使用端口 1935;
RTMPE 在 RTMP 的基础上增加了加密功能;encrypt
RTMPT 封装在 HTTP 请求之上,可穿透防火墙;http–rtmp
RTMPS 类似 RTMPT,增加了 TLS/SSL 的安全功能;

二、RTMP 流媒体播放过程

1、简介

下面分析打开一个 RTMP 流媒体到视音频数据开始播放的全过程。

RTMP 协议规定, 播放一个流媒体有两个前提步骤:

  • 第一步, 建立一个网络连接( NetConnection);
  • 第二步, 建立一个网络流( NetStream)。

其中,网络连接代表服务器端应用程序和客户端之间基础的连通关系。网络流代表了发送多媒体数据的通道。服务器和客户端之间只能建立一个网络连接,但是基于该连接可以创建很多网络流。他们的关系如图所示:

在这里插入图片描述

播放一个 RTMP 协议的流媒体需要经过以下几个步骤:握手,建立连接,建立流,播放。RTMP 连接都是以握手作为开始的。建立连接阶段用于建立客户端与服务器之间的“ 网络连接” ;建立流阶段用于建立客户端与服务器之间的“ 网络流”;播放阶段用于传输视音频数据。

我们分析上面 wireshark 抓到的报文。

2、握手(HandShake)

要建立一个有效的RTMP Connection链接,首先要“握手”:客户端要向服务器发送C0,C1,C2(按序)三个chunk,服务器向客户端发送S0,S1,S2(按序)三个chunk,然后才能进行有效的信息传输。RTMP协议本身并没有规定这6个Message的具体传输顺序,但RTMP协议的实现者需要保证这几点:

  • 客户端要等收到S1之后才能发送C2
  • 客户端要等收到S2之后才能发送其他信息(控制信息和真实音视频等数据)
  • 服务端要等到收到C0之后发送S1
  • 服务端必须等到收到C1之后才能发送S2
  • 服务端必须等到收到C2之后才能发送其他信息(控制信息和真实音视频等数据)

握手开始于客户端发送C0、C1块。服务器收到C0或C1后发送S0和S1。
当客户端收齐S0和S1后,开始发送C2。当服务器收齐C0和C1后,开始发送S2。
当客户端和服务器分别收到S2和C2后,握手完成。

握手示意图如下图所示:
在这里插入图片描述

结合上面理论对比我们抓到的报文:

WireShark 过滤 RTMP 流 :
tcp.port==1935(rtmp+tcp) or rtmpt(rtmp)
rtmpt.header.typeid == 0x08 //过滤音频数据包
rtmpt.header.typeid == 0x09 //过滤视频数据包

我们可以看见TCP的三次握手,因为 RTMP是基于TCP的可靠传输。
在这里插入图片描述
接下去过滤rtmpt协议,rtmp的握手过程如下:

①、客户端向服务器发送握手 C0+C1
在这里插入图片描述

②、服务器向客户端回应握手 S0+S1+S2
在这里插入图片描述
③、客户端向服务器发送握手 C2
在这里插入图片描述
抓包总结:

第一步:客户端发送 C0+C1
第二步:服务端发送 S0+S1+S2
第三步:客户端发送 C2

3、建立网络连接(NetConnection)

包括以下步骤:
在这里插入图片描述

  1. 客户端发起连接请求
  2. 服务器设置客户端的应答窗口大小, 服务器设置客户端的发送带宽大小, 服务器设置客户端的接收块大小
  3. 服务器响应连接结果
  4. 客户端设置服务器的接收块大小

①、客户端发起连接请求
客户端发送命令消息中的“连接” (connect)到服务器, 请求与一个服务应用实例建立连接。

打开connect这个包,最后一个是RTMP协议发送了connect链接消息,查看内容包含推流地址名,但是可以观察到还没有发流名,地址是有app名。
在这里插入图片描述

StreamID是每个消息的唯一标识,划分成Chunk和还原Chunk为Message的时候都是根据这个ID来辨识是否是同一个消息的Chunk的,这里面为0说明这个消息是初始的0消息。

在这里插入图片描述
在这里插入图片描述

Chunk stream ID:message会拆分成多个chunk,同一个Chunk Stream ID必然属于同一个Message。
在这里插入图片描述

message type id(消息的类型id):表示实际发送的数据的类型,如8代表音频数据、9代表视频数据。

例如,Message Type ID在1-7的消息用于协议控制,这些消息一般是RTMP协议自身管理要使用的消息,用户一般情况下无需操作其中的数据。
Message Type ID为8,9的消息分别用于传输音频和视频数据。
Message Type ID为15-20的消息用于发送AMF编码的命令,负责用户与服务器之间的交互,比如播放,暂停等等。

消息首部(Message Header)有四部分组成:标志消息类型的Message Type ID,标志消息长度的Payload Length,标识时间戳的Timestamp,标识消息所属媒体流的Stream ID。消息的报文结构如图3所示。

在这里插入图片描述

在这里插入图片描述

Format:指的是chunk type。共有4种不同的格式,其中第一种格式字段为0,可以表示其他三种表示的所有数据,但由于其他三种格式是基于对之前chunk的差量化的表示,因此可以更简洁地表示相同的数据,实际使用的时候还是应该采用尽量少的字节表示相同意义的数据。因为type0是表示不同数据,其他是差量,所以可以想象如果搜不到type0的包说明这个流肯定有问题。可以通过“rtmpt.header.format == 0”过滤。

②、服务器设置客户端的应答窗口大小、发送带宽大小、接收块大小
服务器接收到连接命令消息后,发送确认窗口大小、发送带宽大小、接收块大小(Window Acknowledgement Size)协议消息到客户端,同时连接到连接命令中提到的应用程序。
在这里插入图片描述
在这里插入图片描述
③、服务器响应创建流结果
服务器发送命令消息中的 “结果” (_result), 通知客户端连接的状态
在这里插入图片描述
④、客户端设置服务器的接收块大小
客户端发送确认窗口大小(Window Acknowledgement Size)协议消息到服务器端。
在这里插入图片描述

4、建立网络流(NetStream)

包括以下步骤:
在这里插入图片描述

  • 客户端发送命令消息中的“创建流” (createStream) 命令到服务器端。
  • 服务器端接收到“创建流” 命令后, 发送命令消息中的“结果” (_result), 通知客户端流的状态
  • 客户端向服务器获取指定流的长度
    ①、客户端发起创建流请求
    在这里插入图片描述

②、服务器响应创建流结果
在这里插入图片描述

③、客户端向服务器获取指定流的长度并设定缓冲区长度
在这里插入图片描述

5、播放(Play)

在这里插入图片描述

  • 客户端发送命令消息中的“播放” (play) 命令到服务器。

  • 服务器发送用户控制消息中的 “stream begin” ,告知客户端流 ID

  • 服务器发送客户端要播放的音频和视频数据
    ①、客户端发送播放请求
    在这里插入图片描述
    该抓包文件中的play命令,transactionID为4,commandObject中没有内容,streamName为“test”,没有duration和reset字段,有start字段,默认值为-2000,2000毫秒,即2s。

    ②、服务器发送 stream begin
    在这里插入图片描述
    播放命令成功的话,服务器发送命令消息中的“响应状态” NetStream.Play.Start & NetStream.Play.reset,告知客户端“播放”命令执行成功。
    在这里插入图片描述
    ③、服务器发送音视频数据给客户端
    在这里插入图片描述
    小的红色框中的数据即为audioTag的header,此处值为0xaf=0x10101111,将二进制隔开为4段: 0x1010=10 0x11=3 0x1=1 0x1=1 对应的值wireshark 已经说明
    在这里插入图片描述
    在这里插入图片描述
    Audio data 示例解析:
    Audio data 0x1210 = 00010 0100 0010 000
    Audio data 0x1310 = 00010 0110 0010 000
    Audio data 0x1188 = 00010 0011 0001 000
    音频类型: 00010 是2 对应LC AAC
    采样率 : 0100 是4 对应 44100 | 0110 是6 对应 24000Hz | 0011是 3 对应 48000
    在这里插入图片描述
    在这里插入图片描述
    VideoData
    1个字节,高4位表示视频帧类型,低4位表示codecID
    第一个字节为0x17,二进制为:0001 0111。所以type=0001=1,codec_id=0111=7,所以表示该视频数据采用H264编码,该帧是关键帧。
    在这里插入图片描述
    PUBLISH 推流
    在这里插入图片描述
    推流从握手开始和前面步骤123一致。
    在这里插入图片描述
    和第四步play区别在于netstream的命令改为publish
    在这里插入图片描述

参考链接

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值