使用libCurl实现断点下载

关键部分代码如下:

#include "curl.h"

#pragma comment(lib, "libcurl.lib")

size_t CROS_DownloadDlg::getContentLengthFunc(void * ptr, size_t size, size_t nmemb, void * stream)
{
LONGLONG len = 0;
int r = sscanf((const char *)ptr, "Content-Length:%I64d\n",&len);
if(r)
*((LONGLONG *) stream) = len;
return size * nmemb;
}

//根据URL获取下载文件大小
LONGLONG CROS_DownloadDlg::getDownloadFileSize(const char*  url)
{
double lensize = 0.0;
for(int iTry = 0 ; iTry < 3 ; iTry ++)//由于curl_easy_perform可能会有偶发性的CURLE_WRITE_ERROR错误,所以添加重试机制
{
CURL *handle = curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_setopt(handle, CURLOPT_HEADER, 1);
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(handle, CURLOPT_NOBODY, 1);
CURLcode res = curl_easy_perform(handle), resGetInfo = CURLE_OK;
if (res == CURLE_OK) {
resGetInfo = curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &lensize);
if(CURLE_OK == resGetInfo){
curl_easy_cleanup(handle);
return (LONGLONG)lensize;
}
}
curl_easy_cleanup(handle);
Sleep(200);
}
return 0;
}

size_t CROS_DownloadDlg::downLoadPackage(void *ptr, size_t size, size_t nmemb, void *userdata)
{
if(!ptr || !userdata)
return 0;
return fwrite(ptr, size, nmemb, (FILE *)userdata);
}

int CROS_DownloadDlg::assetsManagerProgressFunc(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
if(m_bStop)
return -1;
if(totalToDownload > 0.0)
{
CROS_DownloadDlg* pDlg = (CROS_DownloadDlg*)ptr;
pDlg->m_lProcessSize = (LONGLONG)nowDownloaded;
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 1, 0);
}
return 0;
}

/*
0 设置总大小
1 设置当前下载
2 下载完成
3 用户停止下载,其他异常终止下载
4 网络问题引发的下载异常
5 设备断开连接
6 磁盘剩余空间不足
*/
UINT CROS_DownloadDlg::DownloadProc(LPVOID lpParam)

{

//////////////////////////////////////////////////////////////////////////使用CURL实现下载
string sURL = CStringConverter::Unicode2Ansi(strURL.GetString()), sSavePath = CStringConverter::Unicode2Ansi(strSavePath.GetString());

LONGLONG local_file_len = GetFileSize(strSavePath);
pDlg->m_lLocalFileCurSize = local_file_len;
curl_global_init(CURL_GLOBAL_DEFAULT);
LONGLONG remote_file_len = getDownloadFileSize(sURL.c_str());
if(!remote_file_len)
{
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 4, 0);//网络问题获取失败
return 0;
}
pDlg->m_lTotalSize = remote_file_len;
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 0, 0);
if(local_file_len == remote_file_len)
{
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 2, 0);
return 0;
}
//得到准确大小后应判断strSavePath空间是否足够先
if(remote_file_len >= (pDlg->m_ulDiskSpaceMax))
{
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 6, 0);
return 0;
}
FILE *fp = fopen(sSavePath.c_str(), "ab+");
if(!fp)
{
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 3, 0);
return 0;
}
LONGLONG filesize = 0;
m_pCurl = curl_easy_init();//curl初始化
CURLcode res;
curl_easy_setopt(m_pCurl, CURLOPT_URL, sURL.c_str());//设定curl的链接
curl_easy_setopt(m_pCurl, CURLOPT_CONNECTTIMEOUT,5);//设置连接超时,单位秒
curl_easy_setopt(m_pCurl, CURLOPT_HEADERFUNCTION,getContentLengthFunc);
curl_easy_setopt(m_pCurl, CURLOPT_HEADERDATA, &filesize);
curl_easy_setopt(m_pCurl, CURLOPT_RESUME_FROM_LARGE, local_file_len);//断点下载设置
curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, downLoadPackage);
curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, fp);//设置将data写入到文件流fp中
curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);//设置重定位URL,使用自动跳转,返回的头部中有Location(一般直接请求的url没找到),则继续请求Location对应的数据
curl_easy_setopt(m_pCurl, CURLOPT_MAXREDIRS,5);//查找次数,防止查找太深
curl_easy_setopt(m_pCurl, CURLOPT_NOPROGRESS, false);//设为false 下面才能设置进度响应函数
curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSFUNCTION, assetsManagerProgressFunc);//进度响应函数
curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSDATA, pDlg);//数据传输的对象
curl_easy_setopt(m_pCurl, CURLOPT_VERBOSE,1L);
res = curl_easy_perform(m_pCurl);
curl_easy_cleanup(m_pCurl);
curl_global_cleanup();
m_pCurl = NULL;
if (res != CURLE_OK)
{
fclose(fp);
if(res == CURLE_ABORTED_BY_CALLBACK)//点击停止下载
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 3, 0);
else if(res == CURLE_RECV_ERROR)//断网     /* 56 - failure in receiving network data */
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 4, 0);
else
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 3, 0);
return 0;
}
fclose(fp);
pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 2, 0);
return 0;

}

void CROS_DownloadDlg::OnClickBtnStop()
{
if(m_pCurl){
curl_easy_pause(m_pCurl, CURLPAUSE_RECV);
if(IDYES == ShowMessage(IDS_DEF_ROS_SURE_TO_STOP, CiPhoneUtil::GetApplicationName(), SM_ICON_QUESTION|SM_YES_AND_NO)){
m_btnStop.EnableWindow(FALSE);
m_bStop = true;
return;
}
curl_easy_pause(m_pCurl, CURLPAUSE_RECV_CONT);
}
}

http://blog.csdn.net/dingxz105090/article/details/52621614

时间: 2024-08-01 19:30:36

使用libCurl实现断点下载的相关文章

libcurl断点下载遇到的问题

最近游戏把资源(图片.配置.lua)的加载.更新全部改了 ,加载其实还好,就是不走之前的zip解压方式.   以前的大体流程: 下载 –> 启动 –> 解压 –> 更新 –> 进入游戏 现在的大体流程: 下载 –> 启动 –> 更新 –> 进入游戏   之前使用散文件gzip方式更新,现在换成下载zip包(断点下载)   在改动完成之后准备提交appstore,结果崩溃的发现在某些设备上debug可以正常更新.release就始终有问题,一直失败.后来在mac上安

多线程断点下载原理(java代码实例演示)

其实多线程断点下载原理,很简单的,那么我们就来先了解下,如何实现多线程的断点下载,首先:你必须明白第一点,那么就是,什么是多线程下载,该知识点可以查看本博客上一篇文章,Android之多线程下载原理,断点下载呢,其实就是在这个的基础之上添加了一些东西,那么添加了什么东西了,现在来做一个详细的了解. 1.在下载的过程中,边下载,变用一个文件来记录下载的位置,也就是下载了多少的数据 1.创建文件 2.记录下载多少数据 3.存储数据 2.第二次下载的时候,就去读取文件中是否存有数据,读取上次下载的位置

断点下载的请求头设置

断点下载的时候,需要设置请求头的“Range” 表示头100个字节:Range:bytes=0-99 表示第二个100个字节:Range:bytes=100-199 表示最后100个字节:Range:bytes=-100 表示200个字节以后的所有字节:Range:bytes=200-

Java之多线程断点下载的实现

RandomAccessFile类: 此类的实例支持对随机訪问文件的读取和写入.随机訪问文件的行为相似存储在文件系统中的一个大型 byte 数组. 存在指向该隐含数组.光标或索引,称为文件指针.输入操作从文件指针開始读取字节.并随着对字节的读取而前移此文件指针. 假设随机訪问文件以读取/写入模式创建,则输出操作也可用.输出操作从文件指针開始写入字节.并随着对字节的写入而前移此文件指针.写入隐含数组的当前末尾之后的输出操作导致该数组扩展.该文件指针能够通过 getFilePointer 方法读取.

Android的断点下载详细分析二

由于一篇blog写不完,这里是接着上一篇blog的. 写完了MVC中的View,写着我们需要考虑Control层了,他的任务是在后台利用多线程实现断点下载. 先看源码: public class FileDownloader { /* TAG,便于调试 */ private static final String TAG = "FileDownloader"; /* 上下文 */ private Context context; /* 用于对数据库的操作 */ private File

ios ASI 断点下载

ASI的断点下载技术非常的好用, 任何有下载功能的应用都可以试试: //1.创建请求对象 NSURL *url=[NSURL URLWithString:@"在这里输入你的下载链接"]; ASIHTTPRequest *request=[ASIHTTPRequest requestWithURL:url]; //2.设置下载文件保存的路径 NSString *cachepath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirecto

Android/java http多线程断点下载(附源码)

先看下项目结构: http多线程断点下载涉及到 数据库,多线程和http请求等几个模块,东西不是很多,想弄清楚也不是很困难,接下来我和大家分享下我的做法. 一.先看MainActivity.java 成员变量,主要是一些下载过程的变量和handler private String path = "http://192.168.1.3:8080/wanmei/yama.apk"; private String sdcardPath; private int threadNum = 5;

iOS开发网络篇—大文件的多线程断点下载(转)

http://www.cnblogs.com/wendingding/p/3947550.html iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件.因为实现过程较为复杂,所以下面贴出完整的代码. 实现思路:下载开始,创建一个和要下载的文件大小相同的文件(如果要下载的文件为100M,那么就在沙盒中创建一个100M的文件,然后计算每一段的下载量,开启多条线程下载各段的数据,分别写入对应的文件部分). 项目中用到的主要

.net网站的文件上传读取进度条和断点下载

文件上传到服务器时的进度读取 UpfileResult result = new UpfileResult(); try { //先把文件预读到内存里,同时计算上传进度 IServiceProvider provider = (IServiceProvider)HttpContext.Current; // 返回 HTTP 请求正文已被读取的部分. HttpWorkerRequest request = (HttpWorkerRequest)provider.GetService(typeof(