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

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

源代码附上:

 

//全局变量
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);    //不需要body
	if (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为正常下载应该进行的计数, 分别计算即可.