實現
實際就是利用了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,表示分隔符;