实现
实际就是利用了HTTP的分块传输,发送FLV数据,服务器无法知道流长度,所以不会填写Content-Length字段而是携带Transfer-Encoding: chunked字段,这样客户端就会一直接受数据了。
分块传输
编码规则
下面我们来看一下分块传输的编码规则,其实也很简单,同样采用了明文的方式,很类似响应头。
- 每个分块包含两个部分,长度头和数据块;
- 长度头是以 CRLF(回车换行,即\r\n,十六进制中是0d 0a)结尾的一行明文,用 16 进制数字表示长度;
- 数据块紧跟在长度头后,最后也用 CRLF 结尾,但数据不包含 CRLF;
- 最后用一个长度为 0 的块表示结束,即“0\r\n\r\n”。
9
FLV.....
4
....
2df99
.............
理解分块长度
是将长度转换成十六进制,然后将十六进制存储成字符串,然后写入到发送数据里面
例如:
长度为188,313,十六进制为2df99,存储成字符串2df99, 然后填写到发送缓存,通过下面的TCP追踪流可以看到长度的展示
抓包分析
追踪TCP流
可以看到
9 字符串9,代表十六进制的9,表明后面数据长度是9,后面两个字节/r/n,分割
FLV..... FLV的头部数据,刚好是九个字节,后面两个字节/r/n,分割
4 字符串4,代表十六进制的4,表明后面数据长度是4,后面两个字节/r/n,分割
........这里是四个字节,表示前面Tag长度,因为第一个FLV头没有Tag,所以这里是长度为0,后面两个字节/r/n,分割
2df99 字符串2df99,十六进制为2df99,长度为188,313,后面两个字节/r/n,分割
1.请求:
GET /live/1_1.flv HTTP/1.1
Host: 192.168.12.202:8080
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: */*
Referer: http://192.168.12.202:8080/players/srs_player.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
2.响应:
HTTP/1.1 200 OK
Connection: Close
Content-Type: video/x-flv
Server: SRS/6.0.59(Bee)
Transfer-Encoding: chunked//表示启用分块传输
这里注意,因为没有Content-length字段,所以wirshark抓包未识别为HTTP,还是TCP,如下图所示。
3.传输数据
我们可以看到就是基于分块传输的flv数据流:
39是ascii码的9,表示块大小是9;
0d0a就是\r\n,表示分隔符;