在上一篇文章 《面試官不講武德》對Java初級程序猿死命摩擦Http協議 中,咱們有提到大文件下載和斷點續傳,本篇咱們就來開發一個多線程文件下載器,最後咱們用這個多線程下載器來突破百度雲盤下載的限速。git
兄弟們看到這個標題可能會以爲是個標題黨,爲了解決疑慮,咱們先來看下最終的測試結果:面試
測試百度雲下載的文件 46M,本身本地最大下載速度 2M數組
測試結果,提速46倍,我仍是太謙虛了,只說提速30倍,此處咱們以爲應該有掌聲(我聽不到,仍是點贊實在)瀏覽器
源碼地址: https://gitee.com/silently9527/fast-download 服務器
喜歡請記得star哦多線程
Range主要是針對只須要獲取部分資源的範圍請求,經過指定Range便可告知服務器資源的指定範圍。格式: Range: bytes=start-end
ide
好比:
獲取字節範圍 5001-10000post
Range: bytes=5001-10000
也能夠指定開始位置不指定結束位置,表示獲取開始位置以後的所有數據測試
Range: bytes=5001-
服務器接收到帶有Range
的請求,會在處理請求以後返回狀態碼爲206 Partial Content
的響應。ui
基於Range的特性,咱們就能夠實現文件的多線程下載,文件的斷點續傳
本文咱們使用的SpringMVC中的RestTemplate
;因爲百度雲的連接是Https,因此咱們須要設置RestTemplate
繞過證書驗證
RestTemplate
的構造器,以及繞過https的證書驗證由於計算下載速度,咱們須要知道每秒傳輸的字節數是多少,爲了監控傳輸數據的過程,咱們須要瞭解SpringMVC中的接口ResponseExtractor
該接口只有一個方法,當客戶端和服務器端鏈接創建以後,會調用這個方法,咱們能夠在這個方法中監控下載的速度。
DisplayDownloadSpeed
接口的抽象實現 AbstractDisplayDownloadSpeedResponseExtractor
這裏使用的是restTemplate調用execute
, 先文件獲取到字節數組, 再將字節數組直接寫到目標文件。
這裏咱們須要注意的點是: 這種方式會將文件的字節數組所有放入內存中, 及其消耗資源;咱們來看看如何實現。
ByteArrayResponseExtractor
類繼承AbstractDisplayDownloadSpeedResponseExtractor
restTemplate.execute
執行下載,保存字節數據到文件中執行一段時間以後,咱們能夠看到內存已經使用了800M左右,因此這種方式只能使用於小文件的下載,若是咱們下載幾G的大文件,內存確定是不夠用的。至於下載時間,由於文件太大也沒有等下載完成就結束了程序。
上面的方式只能下載小的文件,那大文件的下載咱們該用什麼方式呢?咱們能夠把流輸出到文件而不是內存中。接下來咱們來實現咱們大文件的下載。
FileResponseExtractor
類繼承AbstractDisplayDownloadSpeedResponseExtractor
,把流輸出到文件中執行一段時間以後,咱們再看看下內存的使用狀況,發現這種方式內存消耗較少,效果比較理想,下載時間:199s
若是服務器不限速的話,一般可以把本身本地的帶寬給跑滿,那麼使用單線程下載就夠了,可是若是遇到服務器限速,下載速度遠小於本身本地的帶寬,那麼能夠考慮使用多線程下載。多線程咱們使用CompletableFuture
(能夠參考文章 CompletableFuture讓你的代碼免受阻塞之苦)。
實現多線程文件下載的基本流程:
完成代碼以下:
從執行的結果上來看,由於開啓了30個線程同時在下載,內存的佔用要比單線程消耗的多,可是也在接受範圍內,下載時間:81s,速度提高2.5倍,這是由於idea的下載服務器沒有限速,本次多線程速度的提高僅僅是在充分的壓榨本地的帶寬,因此提示的幅度不大。
由於百度雲盤對單個線程的下載速度作了限制,大概是在100kb,因此咱們使用百度雲盤的下載連接,來測試多線程和單線程的下載速度。
測試 百度雲盤中 46M 的文件的下載速度,本身本地最大下載速度 2M
注意:從瀏覽器中獲取的連接須要先使用URLDecode解碼,不然下載會失敗,而且百度雲盤文件的下載連接是有時效性的,過時後就不能在下載,須要從新生成下載連接
執行的結果能夠看出,百度雲對單線程的下載限速真的是喪心病狂, 46M的文件下載須要耗時: 600s
爲了充分的壓榨網速,找出最合適的線程數,因此測試了不一樣線程數的下載速度
線程數 | 下載總耗時 |
---|---|
10 | 60s |
20 | 30s |
30 | 21s |
40 | 15s |
50 | 13s |
從測試的結果上來看,對於本身的運行環境把線程數設置在30個左右比較合適
文件斷點續傳如何實現,歡迎在你們評論區說出本身的思路。
文中或許會存在或多或少的不足、錯誤之處,有建議或者意見也很是歡迎你們在評論交流。
最後,創做不易,請不要白嫖,但願朋友們能夠點贊評論關注三連,由於這些就是我分享的所有動力來源