仿迅雷实现下载工具,支持断点续传和多线程下载以及简单界面展示

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Chengzi_comm/article/details/53037967

这篇博客介绍一下在公司实习时选做的一个项目,虽然实习期间没有全部完成,但觉得这个项目做好的话挺有意思的,就在之后几天赶着完善了这个项目。 博客最后给出代码地址

这个项目是仿照迅雷,实现一个下载工具。
(开发平台: Ubuntu 16)

功能:能由一个基于HTTP协议的网络资源链接,把该链接对应的资源下载到本地,并且显示下载时的状态(进度条、下载百分比、已下载时间、当前下载速度、自己又在后面加了一个下载的文件名)。要求就是该工具要能支持多线程下载(即同时开启多个下载任务)和断点续传功能(即程序异常退出之后,再次重启时能继续之前未完成的下载任务)以及简单的界面。

下面这幅图是最终的下载界面:
/* * 解释下:
最上面一栏是工具的头部,”Welcome to Thunder” 会在最上面一栏从左到右循环”流动”;
中间一栏有一个”input url > ” 的提示符,需要在这一栏输入要下载资源的链接,回车;
最下面的是工具的主界面,显示现在下载的状况,现在总共有四个下载任务,从左到右依次是 进度条、下载百分比、当前下载速度、已下载时间、下载的文件名。
*/
这里写图片描述

下面按照 【下载原理、单线程断点续传实现原理、界面和多线程】


1、下载原理:

举一个例子来说,我们要下载微信这个应用,http://sw.bos.baidu.com/sw-search-sp/software/97e90d6bfca7b/WeChat_2.2.0.37_Setup.exe 这是微信的下载链接。【如果我们点击这个链接,浏览器就会弹出微信的下载询问界面。这是因为浏览器本身也是一个下载工具】。
我们把这个链接分成三部分,

  • http://
  • sw.bos.baidu.com
  • /sw-search-sp/software/97e90d6bfca7b/WeChat_2.2.0.37_Setup.exe

sw.bos.baidu.com 是百度的一台服务器的域名,后面是资源在该服务器的路径。
首先一个域名可以对应一个ip,我们连接上这台服务器之后,给这台服务器发送一个报文,这是一个请求报文,告诉服务器我们需要这台服务器上 /sw-search-sp/software/97e90d6bfca7b/WeChat_2.2.0.37_Setup.exe 的这个资源,如果请求报文服务器能正确解析了你的请求报文,那它就会把这个资源还是以TCP报文的形式跟你发送一个报文,你只要接收这个响应报文就能得到这个资源了。 从响应报文的什么位置开始是资源,这是HTTP协议的知识;读多少数据结束,这在响应报文的头部信息中有一个 Content-Length: 字段,该字段指示了相应报文消息题的大小。

2、单线程断点续传实现原理

上面说了请求报文,请求报文中有一个字段Range: 字段,如果你想截取请求内容的一部分,那么就不需要请求全部资源,而只需要标识Range: 字段的值就行了。举个例子:如果一个请求资源有100B,你想请求这个资源的全部内容,那么就把Range: 字段标识成 Range: bytes=0- 表示需要发送第0个字节之后的所有字节,或者写成 Range: bytes=0-99 也可以。如果你知道程序最后一个写入文件的断点offset,只需要再次发送请求包,把Range: offset- 给出就可以请求断点之后的所有内容了。这个Range: 字段好像专门为了断点续传而设计的 ^_^。

问题来了, 断点怎么记录,又如何再次发送请求报文?
思路:可以在下载文件时创建一个配置文件,这个配置文件用来记录资源对应的 IP、域名domain、以及资源路径,当然少不了断点信息offset。
具体做法:在开始下载时,首先把资源信息记录到配置文件,然后下载时,每收到一部分资源内容,就把已经写入的总的资源内容大小当作offset,记录到配置文件中。这样当程序挂掉之后,再次重启时,只要检测到当前目录有没有配置文件,就能知道有没有未完成的下载任务。如果有,拿出其中的服务器的资源信息,就能再次连接服务器,并且把Range: 的偏移offset给出,请求余下的内容,继续写入之前的文件。

声明一下:
这样的配置文件这是我刚开始的想法,其实做完多线程就知道这种方法其实不是太好,因为多线程我使用了线程池,每个线程池里的线程都是做的同一类事情,那这样的配置文件信息就不能整合到线程池里去完成。所以如果有多个未完成的下载任务,程序重启时,只能一个一个任务地完成,而不能同时下载其他未完成的任务。等所有之前未完成的任务完成,才能同时开启多个新的下载任务。。。如果没听懂我这句话啥意思,就当我没说吧^_^。当然也可以把配置文件内容改成 url + offset,这样就能复用线程池,使断点续传也能同时下载多个之前未完成的任务,我嫌麻烦就没改。

3、界面和多线程

界面我使用了 ncurses 库,只是简单的实现了一个界面,能输入资源链接和显示输出下载状况。如果对 ncurses 不熟悉,可以自己网上学一下,这里就不重点说了。
多线程我使用了之前写的一个简单的线程池,可配置线程个数。
主函数即主线程使用ncurses在屏幕上画出三个框,然后创建一个线程,去让上面的欢迎界面”动起来”;一旦主线程接收一个url,就把这个url连同线程函数封装成一个”任务”交给线程池的任务队列,一旦任务队列不空,就会有一个线程拿出这个”任务”去执行线程函数去完成这个下载任务。然后主线程继续准备接受下一个url。

如果想要参考代码的话: 在Git上 https://github.com/common1994/Project/tree/master/DownloadTool
代码注释也比较多,相信加上这篇博客理解不难。

这就是一个简洁版的迅雷。

猜你喜欢

转载自blog.csdn.net/Chengzi_comm/article/details/53037967
今日推荐