实现
实际就是利用了HTTP的分块传输,发送FLV数据,服务器无法知道流长度,所以不会填写Content-Length字段而是携带Transfer-Encoding: chunked字段,这样客户端就会一直接受数据了。
分块传输
编码规则
下面我们来看一下分块传输的编码规则,其实也很简单,同样采用了明文的方式,很类似响应头。
- 每个分块包含两个部分,长度头和数据块;
- 长度头是以 CRLF(回车换行,即\r\n)结尾的一行明文,用 16 进制数字表示长度;
- 数据块紧跟在长度头后,最后也用 CRLF 结尾,但数据不包含 CRLF;
- 最后用一个长度为 0 的块表示结束,即“0\r\n\r\n”。
范围请求
HTTP支持按范围获取数据,这样就可以实现点播了。需要添加请求头 Range , 它是 HTTP 范围请求的专用字段,格式是“bytes=x-y”,其中的 x 和 y 是以字节为单位的数据范围。
要注意 x、y 表示的是“偏移量”,范围必须从 0 计数,例如前 10 个字节表示为“0-9”,第二个 10 字节表示为“10-19”,而“0-10”实际上是前 11 个字节。
Range 的格式也很灵活,起点 x 和终点 y 可以省略,能够很方便地表示正数或者倒数的范围。假设文件是 100 个字节,那么:
- “0-”表示从文档起点到文档终点,相当于“0-99”,即整个文件;
- “10-”是从第 10 个字节开始到文档末尾,相当于“10-99”;
- “-1”是文档的最后一个字节,相当于“99-99”;
- “-10”是从文档末尾倒数 10 个字节,相当于“90-99”。
服务器收到 Range 字段后,需要做四件事。
第一,它必须检查范围是否合法,比如文件只有 100 个字节,但请求“200-300”,这就是范围越界了。服务器就会返回状态码 416,意思是“你的范围请求有误,我无法处理,请再检查一下”。
第二,如果范围正确,服务器就可以根据 Range 头计算偏移量,读取文件的片段了,返回状态码“206 Partial Content”,和 200 的意思差不多,但表示 body 只是原数据的一部分。
第三,服务器要添加一个响应头字段 Content-Range,告诉片段的实际偏移量和资源的总大小,格式是“bytes x-y/length”,与 Range 头区别在没有“=”,范围后多了总长度。例如,对于“0-10”的范围请求,值就是“bytes 0-10/100”。
最后剩下的就是发送数据了,直接把片段用 TCP 发给客户端,一个范围请求就算是处理完了。
抓包分析
1.请求:
GET /live/livestream.flv HTTP/1.1 User-Agent: Lavf/58.29.100 Accept: */* Range: bytes=0- // 这里表示从0到数据结束 Connection: close // 表示发送完就结束,不是默认的keep-alive Host: 10.160.58.155:8080 Icy-MetaData: 1
2.响应:
HTTP/1.1 200 OK Connection: Keep-Alive Content-Type: video/x-flv Server: SRS/3.0.156(OuXuli) Transfer-Encoding: chunked //表示启用分块传输
这里注意,因为没有Content-length字段,所以wirshark抓包未识别为HTTP,还是TCP,如下图所示。
3.传输数据
我们可以看到就是基于分块传输的flv数据流:
39是ascii码的9,表示块大小是9;
0d0a就是\r\n,表示分隔符;