RTMP协议基础知识
RTMP协议定义:
RTMP的全称为Real Time Message Protocol,即实时传输协议;它是基于TCP协议之上的一个应用协议;
应用场景:
他是adobe公司开发的用于客户机和服务器之间实时传输音频和视频实的一个协议;目前广泛应用于直播领域
协议格式介绍:
在RTMP协议中存在message和chunk的概念;message是指一个需要传输的数据,<br>而当数据过大之后,不能再一个协议包中传输,这样的话,就需要将这个数据分多次传输到对端去,每次传输的就称之为chunk;所以chunk和message具有归属关系,chunk一定会会归属于一个message;一个message至少包含有一个chunk;为了保证传输数 据的正确,我们为message和chunk都定义了一个消息头;
用一个比较好理解的例子来说就是:我们有一堆沙子需要从采砂场运送到施工工地去,但是这对沙子可能很多,一车运送不过去,我们可以分多次,将他运送过去;在这个例子中,这对沙子就是message,而每一车沙子就是一个chunk,运送沙子的车子就好比是网络。所以,在实际的传输过程中,一车沙子是最小的传输单元;
而为了保证这些沙子在运输过程中不弄出错,每车运输的沙子中,我们都放放一些标志信息,用以标记这车沙子自己的一些基本信息,同时也会放上这车沙子所属的这堆沙子的信息;用以标记这车沙子的信息的标识为Basic header,用以标记这车沙子的信息的标致为Message header
协议格式:
上述为RTMP协议在传输过程中的一个完整的chunk的协议格式,从上面的协议格式可以看出,一个完正的chunk包由4部分组成;分别为:BasicHeader、MeaasgeHeader、ExternTime和ChunkDate;接下来我们分别介绍这四部分
- BasicHeader:
BasicHeaser是一个可变长度的报文头,它包含chunkType和csid两个字段,其中chunktype占用2bit的长度,csid则占用剩余的bit长度;如下图:
ChunkType: 表示这个chunk包的类型;由于该字段占用2bit,也就是可以取{0,1,2,3}中的任意一个值,其中每个值表示不同的涵义,他的取值也会决定着Message Header占用的字节长度;
Csid: 它是chunk stream id的缩写,表示当前这个包所属流的通道编码,通过字段的取值,可以唯一确定一个流。他的长度可能为6bit,也可能1byte或者2byte;需要注意的是, 0、1、2是csid保留的取值;
根据上面就的描述,由于csid的长度为可变长度,所以,整个BasicHeader的长度也是可变的,最短的话则为1byte,长的话可以为3byte;
需要注意的是:
由于csid是可变的,可以取6bit,也可以取值1byte或者2byte,所以为了为了在解析的时候,便于区分,rtmp协议做了如下规定:
1、 当csid占用6个bit的时候,与chunktype所在同一字节中剩余的6bit的取值为csid的取值
2、 当csid取值为1byte的时候,与chunktype所在的同一字节剩余的6bit取值为0,csid的取值范围为64+[64+256)取值
3、 当与chunktype所在的同一字节剩余的6bit取值为1的时候,表示BasicHeader占3Byte;csid的取值范围为:256*3Byte取值+2Byte取值+64
4、 当与chunkType所在的剩余6bit取值为2的时候,表示一些控制消息
- MessageHeader:
该头部信息包含了要发送的实际数据的描述信息,完成的MessageHeader由TimeStamp、MessageLength、MessageTypeID和MessageStreamID四部分组成;如下图
TimeStamp: 表示该包数据的时间戳,占用3Byte数据长度,所以他的取值范围为[0~0xFFFFFF),当该字段的值超过最大时,可以到跟在MessageHeader后面的扩展字段区域获取时间值,也就是ExternTime字段
接收端何时去获取ExternTime字段的值作为真正的时间取值呢?当TimeStamp字段不能够存储下时间值的时候,发送端会将该字段的3Byte的各个bit为全部设置为1,这样话,在接收端,当检测到Timestamp字段的bit位置全部为1时,则获取ExternTime的值作为真正的时间值。
MessageLength: 消息数据长度,占用3Byte;表示当前chunk所属message的数据长度,而不是当前传输的这个chunk的数据的长度;如此来说,同一个message的不同的chunk数据包中的钙字段的取值是相同的;
MessageTypeID: 消息类型,占用1个字节,是用来区分当前这个message的数据的类型,针对于不同的取值,表示不同的涵义,后续将会专门介绍;
MessageStreamID: 消息流的id,占用4byte;其取值与BasicHeader中的csid的涵义相一至,需要注意的是,该字段采用小端存储,所以在赋值和取值的时候需要注意。
上面的MessageHeader是一个完整的包头,总共占有11Byte;前面介绍BasicHeader的时候提到过,BasicHeader中的ChunkType字段的取值,会决定后面MessageHeader包头的长度,而ChunkType字段的可以取值为{0,1,2,3}四个中的任意一个。
1、 当chunkType=0时,整个MessageHeader的各个字段都存在;共占有11Byte长度,如下图所示
2、 当chunkType=1时,MessageHeader中包含TimeStamp、MessageLength、 MessageTypeID三个字段,共占有7Byte长度,如下图:
3、 当chunkType=2时,MessageHeader中仅有TimeStamp字段,总共占有3Byte的长度,如下图所示:
4、 当chunkType=3时,MessageHeader的长度为0,表示与前一个chunk的MessageHeader的值是一样的,当一个Message拆分为多个chunk传输的时候,一般会使用这种传输方式
- ExternTime:
该字段是一个扩展字段,不一定存在,只有当MessageHeader字段中的Timestamp字段不能够存储下时间戳的时候,才会存在该字段,该字段占有4Byte的长度
- ChunkData:
该字段为一个chunk包中携带的数据的长度,默认的一个chunk包的长度为128Byte,去除掉头部字节之后,就是ChunkData的数据长度,所以,ChunkData的数据长度为:128-BasicHeaderLength-MessageHeaderLength;
MeaageHeader中的MessageTypeID字段:
上面有提到,MessageTypeID表示消息类型,每个消息都有一个类型,针对于不同的消息类型,有不同的涵义,我们可以根据MessageTypeID字段解析出来的消息类型进行相应的处理;
在RTMP协议格式中规定,当消息为控制消息的时候,MessageHeader的MessageStreamID由必须设置为0,并且BasicHeader的csid字段必须设置为2;由此可以得出,BasicHeader的chunkType必须设置为0;
所以当消息为控制消息的时候,整个chunk包的头是一个完成的报文头。总共会占有12Byte;
1、MessageTypeID=1表示设置chunk的size,默认的四则是128字节,收发数据的双方可以使用该i消息进行相互的设置
2、MessageTypeID=2表示中断消息,当一方正在等待对方发送的一个Message消息中的其他chunk消息,收到该消息之后,就没有必要在处理之后受到的该message中的其他chunk消息了
3、MessageTypeID=3是应答消息
4、MessageTypeID=5应答窗口消息,是对MessageTypeID=1的应答
5、MessageTypeID=6是设置带宽流的消息,该消息使用MessageTypeID=3进行应答
6、MessageTypeID取值为17(AMF3)或者20(AFM0)的时候,是客户端和服务端在进行某些执行命令的传输,而执行命令使用的是amf格式的数据进行传输的
7、MessageTypeID取值为15(AMF3)或者18(AFM0)传递的是一些音视频的元数据或者用户自定义的命令,同样,这些数据使用的是amf格式的数据
8、MessageTypeID取值为16(AMF3)或者19(AFM0),是共享数据的传输
9、MessageTypeID=8为音频数据
10、MessageTypeID=9为视频数据
11、MessageTypeID=4用户控制消息,用以用户对流的控制,与协议控制消息是由区别的
12、MessageTypeID=22为聚合消息,是多个rtmp子消息的集合。