在上一篇文章 《面试官不讲武德》对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个左右比较合适
文件断点续传如何实现,欢迎在你们评论区说出本身的思路。
文中或许会存在或多或少的不足、错误之处,有建议或者意见也很是欢迎你们在评论交流。
最后,创做不易,请不要白嫖,但愿朋友们能够点赞评论关注三连,由于这些就是我分享的所有动力来源