在讲解connect消息的时候,我们说过服务器收到connect消息之后,会向客户端发送Window Acknowledgement Size消息和Set Peer Bandwidth消息,这一篇就来介绍一下这两条消息。
1.概览
首先从抓包文件看一下:
示例中服务器ip地址是192.17.1.200,客户端ip地址是192.17.1.92,客户端向服务器发送connect消息之后,服务器向客户端发送了Window Acknowledgement Size和Set Peer Bandwidth消息。
2.Window Acknowledgement Size消息
Window Acknowledgement Size用来通知对端,如果收到该大小字节的数据,需要回复一个Acknowledgement消息,也就是ACK。本例中,设置的大小为500000,也就是服务端通知客户端如果收到了50000字节的数据,需要向服务端发送一个ACK的消息,而实际上一般情况一个会话中能达到如此大的数据量比较少,所以我们也看到会回复ACK消息的消息比较少,更多的只是看到设置接收窗口大小的消息(Window Acknowledgement Size),接下来我们看一下抓包。
消息格式比较简单,组织结构是RTMP Header + RTMP Body,Header的结构就不赘述了,参考前面的文章;Body中直接使用4个字节表示要设置的大小,此处为0x004c4b40=5000000。
3.Acknowlegement消息
Acknowlegement消息可以理解为Window Acknowlegement Size满足条件的触发消息,当一端收到的数据大小满足Window Acknowledgement Size设置的大小时,向对端发送Ack消息。
Acknowlegement消息,也按照RTMP Header + RTMP Body进行组织,其Body也直接使用4个字节,表示收到数据满足Window Acknowledgement Size的最后一个数据包的序列号。我们来看一个抓包文件:
该条消息表示,在序列号为2507670的时候,rtmp客户端已累计收到5000000个字节的数据,此时向服务端发送一个ACK。
另外我们也验证一下,交互过程中,更多的看到Window Acknowledgement Size消息,而很少看到Acknowlegement消息。
说明:wireshark中可以针对rtmp消息进行过滤
过滤Window Acknowledgement Size
rtmpt.header.typeid == 0x05
过滤Acknowledgement
rtmpt.header.typeid == 0x03
照猫画虎,可以对照下表进行过滤:
typeID |
消息类型 |
说明 |
0x00 |
Unkown |
|
0x01 |
Set Chunk Size |
设置Chunk大小 |
0x02 |
Abort |
|
0x03 |
Window Acknowledgement Size |
|
0x04 |
User Control Message |
空户控制消息(如Stream Begin等) |
0x05 |
Acknowledgement |
|
0x06 |
Set Peer Bandwidth |
更多的关于wireshark抓包关于rtmp的过滤条件,参照:
https://www.wireshark.org/docs/dfref/r/rtmpt.html
4.Set Peer BandWidth消息
该消息里设置对端输出带宽,对端是通过设置Window Acknowledgement Size来实现流量控制的。超过Window Acknowledgement Size后未确认(不发送Acknowledgement)发送端将不再发送消息。所以对端收到set peer bandwidth后,如果之前发送的Window Acknowledgement Size和这里写的的Window Acknowledgement Size不一样,一般会发送一个Window Acknowledgement Size。
刚开始建立连接,服务器向客户端发送Set Peer Bandwidth消息,客户端第一次收到Set Peer Bandwidth消息,之前没有发送过Window Acknowledgement Size,所以在这里向服务端发送一次消息。
还是看抓包文件:
Set Peer Bandwidth消息还是按照RTMP Header + RTMP Body的格式组成。RTMP Body由两个字段组成,一个是Window acknowledgement size,占用4个字节;一个是limit type,表示限制的类型,可取的值为0(Hard),1(soft), 2(Dynamic)。本例中采用的是Dynamic。
limity type表示了不同的限制策略:
Hard:收到消息的一端需要按照消息中设置的Window size进行限制;
Soft:收到消息的一端按照消息中设置的Window size或者已经生效的限制进行限制,以两者中较小的为准。
Dynamic:如果之前的类型为Hard,则此消息也为Hard类型,否则忽略该类型。
5.StreamBegin
服务端发送Set Peer Bandwidth消息之后,客户端向服务端发送Window Acknowledgement Size消息,服务端再向客户端发送一条用户控制消息StreamBegin。
wireshark中过滤StreamBegin消息的条件如下:
rtmpt.header.typeid == 0x04 and rtmpt.ucm.eventtype == 0x00
StreamBegin属于用户控制类消息,header的typeid为0x04。而用户控制消息的类型的定义如下:
type |
消息 |
说明 |
0x00 |
Stream Begin |
|
0x01 |
Stream EOF |
|
0x02 |
Stream Dry |
|
0x03 |
SetBufferLength |
|
0x04 |
StreamIsRecoreded |
|
0x06 |
PingRequest |
|
0x07 |
PringResponse |
如此,我们就得出了StreamBegin的过滤条件。接下来我们看看StreamBegin消息,还是先看一下抓包文件:
RTMP服务器发送StreamBegin以通知客户端流已经可以使用并且可以用于通信。默认情况下,从客户端成功接收到connect命令后,将在ID 0上发送StreamBegin。StreamBegin的数据字段占用4字节,其类型占用2个字节,所以RTMP Body部分总共占用6个字节(类型+数据)。其中数据字段代表已开始运行的流的流ID,此例中为1。
好了,这一篇就到这里了,下一篇我们继续手撕Rtmp协议细节,不要走远!
扫描二维码获取更多精彩