在讲解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。
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协议细节,不要走远!