成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

視頻播放、斷點續(xù)傳、多線程下載實現(xiàn)基礎:Range

MockingBird / 3979人閱讀

摘要:如獲取字節(jié)的數(shù)據(jù)和到結(jié)尾的數(shù)據(jù)該頭部指定了響應的數(shù)據(jù)的內(nèi)容范圍,語法格式如下說明數(shù)據(jù)區(qū)間所采用的單位。

實現(xiàn)一個視頻播放的功能,以及對大文件的下載操作等等都避不開一個點:獲取文件任意位置的數(shù)據(jù),如果說我們單純的通過 echo file-content 的方式只能用于文件下載,如果視頻文件用于播放中,則難以處理,具體表現(xiàn)則為視頻播放的時候無法調(diào)整進度條,而且如果是視頻網(wǎng)站,對于視頻只采用放在某個可以直接訪問的目錄上,那么這個視頻也就相當于公開了,對于什么 VIP 什么的也就無從說起,本篇文章將 Range,來提供視頻播放、斷點續(xù)傳、多線程下載的技術依賴實現(xiàn)

Range

HTTP協(xié)議中,支持以 Range 的形式指定獲取資源的特定偏移的數(shù)據(jù),語法格式如下,具體參考 Range: MDN:

Range: =-
Range: =-
Range: =-, -
Range: =-, -, -

只能是 bytes (目前來說),指定單位

一個整數(shù),表示在特定單位下,范圍的起始值。

一個整數(shù),表示在特定單位下,范圍的結(jié)束值。這個值是可選的,如果不存在,表示此范圍一直延伸到文檔結(jié)束。

如: 獲取 0-100 字節(jié)的數(shù)據(jù)和120到結(jié)尾的數(shù)據(jù)

Range: bytes=0-100,120-
Content-Range

該頭部指定了響應的數(shù)據(jù)的內(nèi)容范圍,語法格式如下:

Content-Range:  -/
Content-Range:  -/*
Content-Range:  */

說明:

數(shù)據(jù)區(qū)間所采用的單位。通常是字節(jié)(bytes)。

一個整數(shù),表示在給定單位下,區(qū)間的起始值。

一個整數(shù),表示在給定單位下,區(qū)間的結(jié)束值。

整個文件的大?。ㄈ绻笮∥粗獎t用 "*" 表示)

例如:

Content-Range: bytes 200-1000/67589
多Range響應

目測在網(wǎng)絡上面的都沒有說到,但是HTTP協(xié)議支持多Range,具體返回內(nèi)容信息格式如下:

GET http://suda.dev.dx/file HTTP/1.1
Host: suda.dev.dx
Connection: keep-alive
Accept-Encoding: identity;q=1, *;q=0
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Safari/537.36
Accept: */*
Referer: http://test.dev.dx/video.html
Accept-Language: zh-CN,zh;q=0.9
Cookie: php_session=8eec314af63d994c2eeb1baca7487332
Range: bytes=0-1,2-3


HTTP/1.1 206 Partial Content
Date: Sun, 10 Mar 2019 09:36:59 GMT
Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j mod_fcgid/2.3.9
X-Powered-By: PHP/7.2.1
Accept-Ranges: bytes
Content-Length: 220
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: multipart/byteranges; boundary=multiple_range_ss6bBSB6IlLi0YPpP8rK3g==

--multiple_range_ss6bBSB6IlLi0YPpP8rK3g==
Content-Type: video/mp4
Content-Range: bytes 0-1/132006090

<...somedata...>
--multiple_range_ss6bBSB6IlLi0YPpP8rK3g==
Content-Type: video/mp4
Content-Range: bytes 2-3/132006090

<...somedata...>
Accept-Rangs

服務器響應,告訴瀏覽器是否支持 Range,

語法:

Accept-Ranges: bytes
Accept-Ranges: none

none
不支持任何范圍請求單位,由于其等同于沒有返回此頭部,因此很少使用。不過一些瀏覽器,比如IE9,會依據(jù)該頭部去禁用或者移除下載管理器的暫停按鈕。

bytes
范圍請求的單位是 bytes (字節(jié))

實現(xiàn)代碼

本實現(xiàn)代碼可以簡單理解為偽代碼,部分依賴沒有給出,Swoole 環(huán)境下修改一下即可使用。

使用代碼:
onRequest($request, $response);
    }
}
依賴代碼:
file = $file instanceof SplFileObject? $file : new SplFileObject($file);
        $this->mime = MimeType::getMimeType($this->file->getExtension());
    }

    /**
     * 處理文件請求
     *
     * @param sudaframeworkRequest $request
     * @param sudaframeworkResponse $response
     * @return void
     */
    public function onRequest(Request $request, Response $response)
    {
        $ranges = $this->getRanges($request);
        $response->setHeader("accept-ranges", "bytes");
        if ($ranges === false || $request->getMethod() !== "GET") {
            $response->status(400);
        } elseif ($ranges === null) {
            $response->sendFile($this->file->getRealPath());
        } elseif (count($ranges) === 1) {
            $response->status(206);
            $range = $ranges[0];
            $response->setHeader("content-type", $this->mime);
            $response->setHeader("content-range", $this->getRangeHeader($range));
            $this->sendFileByRange($response, $range);
        } else {
            $response->status(206);
            $this->sendMultipleFileByRange($response, $ranges);
        }
    }

    /**
     * 發(fā)送多Range
     *
     * @param sudaframeworkResponse $response
     * @param array $ranges
     * @return void
     */
    protected function sendMultipleFileByRange(Response $response, array $ranges)
    {
        $separates = "multiple_range_".base64_encode(md5(uniqid(), true));
        $response->setHeader("content-type", "multipart/byteranges; boundary=".$separates);
        foreach ($ranges as $range) {
            $response->write("--".$separates."
");
            $this->sendMultipleRangePart($response, $range);
            $this->sendFileByRange($response, $range);
            $response->write("
");
        }
    }


    /**
     * 發(fā)送范圍數(shù)據(jù)
     *
     * @param sudaframeworkResponse $response
     * @param array $range
     * @return void
     */
    protected function sendFileByRange(Response $response, array $range)
    {
        $response->write(new DataStream($this->file->getRealPath(), $range["start"], $range["end"] -  $range["start"] + 1));
    }

    /**
     * 獲取Range描述
     *
     * @param sudaframeworkRequest $request
     * @return array|bool|null
     */
    protected function getRanges(Request $request)
    {
        $ranges = $this->parseRangeHeader($request);
        if (is_array($ranges)) {
            return $this->parseRanges($ranges);
        } elseif ($ranges === false) {
            return false;
        }
        return null;
    }

    /**
     * 寫Range頭
     *
     * @param sudaframeworkResponse $response
     * @param array $range
     * @return void
     */
    protected function sendMultipleRangePart(Response $response, array $range)
    {
        $response->write("Content-Type: ".$this->mime."
");
        $response->write("Content-Range: ".$this->getRangeHeader($range) ."

");
    }

    /**
     * 生成Range頭
     *
     * @param array $range
     * @return string
     */
    protected function getRangeHeader(array $range):string
    {
        return sprintf("bytes %d-%d/%d", $range["start"], $range["end"], $this->file->getSize());
    }

    /**
     * 獲取Range描述
     *
     * @param sudaframeworkRequest $request
     * @return array|bool|null
     */
    protected function parseRangeHeader(Request $request)
    {
        $range = $request->getHeader("range", null);
        if (is_string($range)) {
            $range = trim($range);
            if (strpos($range, "bytes=") !== 0) {
                return false;
            }
            $rangesFrom = substr($range, strlen("bytes="));
            return explode(",", $rangesFrom);
        }
        return null;
    }
    
    /**
     * 處理范圍
     *
     * @param array $ranges
     * @return array|bool
     */
    protected function parseRanges(array $ranges)
    {
        $range = [];
        foreach ($ranges as  $value) {
            if (($r = $this->parseRange($value)) !== null) {
                $range[] = $r;
            } else {
                return false;
            }
        }
        return $range;
    }

    /**
     * 處理Range
     *
     * @param string $range
     * @return array
     */
    protected function parseRange(string $range):?array
    {
        $range = trim($range);
        if (strrpos($range, "-") === strlen($range) - 1) {
            return [
                "start" => intval(
trim($range, "-")),
                "end" => $this->file->getSize() - 1,
            ];
        } elseif (strpos($range, "-") !== false) {
            list($start, $end) = explode("-", $range, 2);
            return ["start" => intval($start) , "end" => intval($end) ];
        }
        return null;
    }
}
參考文獻

https://tools.ietf.org/html/r...

https://tools.ietf.org/html/r...

https://developer.mozilla.org...

https://developer.mozilla.org...

完整代碼

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/30972.html

相關文章

  • 練習項目備選清單

    摘要:練習項目備選清單文件下載器功能概要設計實現(xiàn)新建下載功能以為基礎給出下載鏈接可以啟動下載任務實現(xiàn)局域網(wǎng)內(nèi)下載傳輸文件以單線程下載方式實現(xiàn)附加功能支持斷點續(xù)傳實現(xiàn)多線程下載實現(xiàn)下載參考技術套接字編程多線程編程音視頻播放器功能概要設計實現(xiàn)播放常見 練習項目備選清單 Utilities 1. 文件下載器 功能概要設計: 實現(xiàn)新建下載功能(以ftp為基礎) 給出下載鏈接可以啟動下載任務 實現(xiàn)局...

    guyan0319 評論0 收藏0
  • 練習項目備選清單

    摘要:練習項目備選清單文件下載器功能概要設計實現(xiàn)新建下載功能以為基礎給出下載鏈接可以啟動下載任務實現(xiàn)局域網(wǎng)內(nèi)下載傳輸文件以單線程下載方式實現(xiàn)附加功能支持斷點續(xù)傳實現(xiàn)多線程下載實現(xiàn)下載參考技術套接字編程多線程編程音視頻播放器功能概要設計實現(xiàn)播放常見 練習項目備選清單 Utilities 1. 文件下載器 功能概要設計: 實現(xiàn)新建下載功能(以ftp為基礎) 給出下載鏈接可以啟動下載任務 實現(xiàn)局...

    peixn 評論0 收藏0
  • Android Okhttp 斷點續(xù)傳面試解析

    摘要:怎么支持斷點續(xù)傳的協(xié)議中默認支持獲取文件的部分內(nèi)容,這其中主要是通過頭部的兩個參數(shù)和來實現(xiàn)的。我們在刷一下面試題的時候,有時候會看到一些大廠會問關于斷點續(xù)傳的原理,那么今天在這里從 HTTP 斷點續(xù)傳知識和 Android 中如何實現(xiàn)斷點續(xù)傳的思路來做一個關于 Android 斷點續(xù)傳原理的總結(jié)。 Http 斷點續(xù)傳知識點 什么是斷點續(xù)傳 指的是在上傳/下載時,將任務(一個文件或壓縮包)人為...

    ACb0y 評論0 收藏0
  • python初學——網(wǎng)絡編程之FTP服務器支持并發(fā)版本

    摘要:擴展支持多用戶并發(fā)訪問與線程池。項目請見初學網(wǎng)絡編程之服務器。不允許超過磁盤配額。該文件是一個使用模塊編寫的線程池類。這一步就做到了線程池的作用。 對MYFTP項目進行升級。擴展支持多用戶并發(fā)訪問與線程池。MYFTP項目請見python初學——網(wǎng)絡編程之FTP服務器。 擴展需求 1.在之前開發(fā)的FTP基礎上,開發(fā)支持多并發(fā)的功能2.不能使用SocketServer模塊,必須自己實現(xiàn)多線...

    oysun 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<