(四)使用Libcurl下载文件,解决无信号中断,下载中掉电恢复后断点续传问题的源代码

来源:互联网 发布:91白苹果修复软件 编辑:程序博客网 时间:2024/06/08 06:57

源代码附上:

 

//全局变量bool resumeDownload = false;//是否需要下载的标记位long downloadFileLenth = 0;//需要下载的总大小, 远程文件的大小
/* 得到本地文件大小的函数, 若不是续传则返回0, 否则返回指定路径地址的文件大小 */long getLocalFileLenth(const char* localPath){if (!resumeDownload){return 0;}return fs_open(localPath).fs_size();}
/* 得到远程文件的大小, 要下载的文件大小 */long getDownloadFileLenth(const char *url){long downloadFileLenth = 0;CURL *handle = curl_easy_init();curl_easy_setopt(handle, CURLOPT_URL, url);curl_easy_setopt(handle, CURLOPT_HEADER, 1);    //只需要header头curl_easy_setopt(handle, CURLOPT_NOBODY, 1);    //不需要bodyif (curl_easy_perform(handle) == CURLE_OK) {curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth);} else {downloadFileLenth = -1;}return downloadFileLenth;}
/* scomoDownload回调的计算进度条的函数 */void getProgressValue(const char* localSize, double dt, double dn, double ult, double uln){double showTotal, showNow;showTotal = downloadFileLenth;int localNow = atoi (localSize.c_str());showNow = localNow + dn;showProgressBar(showTotal, showNow);}
/* 直接进行下载的函数 */public CurlCode scomoDownload(long timeout) {long localFileLenth = getLocalFileLenth();const char *localFileLenthStr;sprint(localFileLenthStr, %ld, localFileLenth);curl_easy_setopt(handle, CURLOPT_URL, mUrl);curl_easy_setopt(handle, CURLOPT_HEADER, 0);curl_easy_setopt(handle, CURLOPT_TIMEOUT, timeout);curl_easy_setopt(handle, CURLOPT_CONNECTIONTIMEOUT, 0);curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &writeDataCallback); curl_easy_setopt(handle, CURLOPT_WRITEDATA, this);curl_easy_setopt(handle, CURLOPT_RESUME_FROM_LARGE, localFileLenth); curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0);curl_easy_setopt(handle, CURLOPT_ PROGRESSFUNCTION, getProgressValue); curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, localFileLenthStr);if (curl_easy_perform) {resumeDownload = true;return DS_FAILED;} else {resumeDownload = false;return DS_FINISHED;}}
/* downloadControl函数用来控制整个下载过程的节奏, 控制下载的次数, 每次等待的时间等 */public void downloadControler(){downloadFileLenth = getDownloadFileLenth();//下载前得到要下载的文件大小赋值给全局变量int times = 605;//600次*50ms=5分钟, 以此确保5分钟内的重试次数, 而5次是正常下载的中断次数, 意思即是5次内能正常完成下载.int count = 0;int timeout = 30;DSTATUS dstatus = DS_FAILED;while (count++ < times){status = scomoDownload(timeout);if (dstatus == DS_FINISHED){break;}Thread.sleep(500);//每次下载中间间隔500毫秒}resumeDownload = false;//不管下载成功或失败, 完成while循环后将标志回位if (dstaus == DS_FINISHED) {updateApp();//执行软件安装的操作…}SAFE_DELETE(localFile);//流程最后要确保本地文件删除}

resumeDownload是一个非常重要的标记位,主要用来标识是否需要续传下载,在初始化时为false,在下载完成后也应回位成false,下载过程中若因时间中断未下载完成也为false.

处理下载中掉电后续传也需要这个标记位, 在程序启动时,进行检测,若上次没下载完,修改标志位为true,然后调用下载入口函数downloadController:

      if (scomo_status == 30){

             resumeDownload = true;

             downloadController();

}

 

若下载环境正常, 1个小时内可以完成的下载可以直接使用此方案来下载,不用修改控制,但若是超过1小时的下载,需要将本方案进行改进.基本上就是将605那里分开判断600+x,其中600为每次断网后应重试的次数, x为正常下载应该进行的计数,分别计算即可.


 

原创粉丝点击