转载文章 http://blog.csdn.net/robertbaker/article/details/43703907
转载文章 http://blog.csdn.net/infoworld/article/details/46646933
谢谢版主
一、使用libcurl实现的下载器
libcurl的主页:http://curl.haxx.se/
头文件:
/**********************************************************************
* Copyright (C) 2014 - - All Rights Reserved
*
* 文件名称: Downloader_LibCurl.h
* 摘 要: 下载器 - LibCurl实现
*
* 作 者: yanglinbo,
* 修 改: 查看文件最下方.
*
***********************************************************************/
#ifndef __Downloader_LibCurl_H__
#define __Downloader_LibCurl_H__
#include <curl/curl.h>
#include <fstream>
#include <string>
class CDownloader
{
public:
CDownloader(void);
virtual ~CDownloader(void);
public:
/// 线程入口函数
virtual bool run();
/// 启动下载
virtual bool start(const std::string& strUrl, const std::string& strLocalFile);
/// 停止下载
virtual bool stop();
/// 是否运行状态
bool isRunning() const;
protected:
/// 写入回调
static size_t handleWrite(void *buffer, size_t size, size_t nmemb, void *userp);
/// 进度回调
static size_t handleProgress(void *buffer, double dltotal, double dlnow, double ultotal, double ulnow);
protected:
/// 写入回调
size_t onWrite(void *buffer, size_t size, size_t nmemb);
/// 进度回调
size_t onProgress(const double& dltotal, const double& dlnow);
/// 下载回调
void onDownload();
protected:
/// 设置libcurl选项
void setOption();
/// 清除数据
void clear();
protected:
CURL* m_pCurl; ///< libcurl句柄
FILE* m_pFile; ///< 文件指针
bool m_bRunning; ///< 运行标志
std::string m_strDownloadUrl; ///< 下载链接
std::string m_strLocalFilePath; ///< 本地文件路径
};
#endif
实现文件:
/**********************************************************************
* Copyright (C) 2014 - - All Rights Reserved
*
* 文件名称: Downloader_LibCurl.cpp
* 摘 要: 下载器 - LibCurl实现
*
* 作 者: yanglinbo,
* 修 改: 查看文件最下方.
*
***********************************************************************/
#include "StdAfx.h"
#include "Downloader.h"
CDownloader::CDownloader(void)
: m_pCurl(NULL)
, m_pFile(NULL)
, m_bRunning(false)
{
}
CDownloader::~CDownloader(void)
{
stop();
}
bool CDownloader::run()
{
onDownload();
return true;
}
bool CDownloader::isRunning() const
{
return m_bRunning;
}
void CDownloader::clear()
{
if (m_pFile)
{
fclose(m_pFile);
m_pFile = NULL;
}
if (m_pCurl)
{
curl_easy_cleanup(m_pCurl);
m_pCurl = NULL;
curl_global_cleanup();
}
m_strDownloadUrl.clear();
m_strLocalFilePath.clear();
}
void CDownloader::setOption()
{
// 远程URL,支持 http, https, ftp
curl_easy_setopt(m_pCurl, CURLOPT_URL, m_strDownloadUrl.c_str());
// 设置User-Agent
std::string useragent = _T("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1");
curl_easy_setopt(m_pCurl, CURLOPT_USERAGENT, useragent.c_str());
// 设置重定向的最大次数
curl_easy_setopt(m_pCurl, CURLOPT_MAXREDIRS, 5);
// 设置301、302跳转跟随location
curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(m_pCurl, CURLOPT_POST, false);
// 下载内容回调函数
curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, handleWrite);
curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, this);
// 进度回调函数
curl_easy_setopt(m_pCurl, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSDATA, this);
curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSFUNCTION, handleProgress);
// 跳过服务器SSL验证,不使用CA证书
curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, 0L);
// 验证服务器端发送的证书,默认是 2(高),1(中),0(禁用)
curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, 0L);
}
bool CDownloader::start(const std::string& strUrl, const std::string& strLocalFile)
{
if (strUrl.empty()) return false;
if (m_bRunning == true) return true;
clear();
m_strDownloadUrl = strUrl;
m_strLocalFilePath = strLocalFile;
// 初始化libcurl
m_pCurl = curl_easy_init();
if (m_pCurl == NULL)
{
return false;
}
// 设置libcurl的选项
setOption();
// 创建文件
m_pFile = fopen(m_strLocalFilePath.c_str(), "wb");
if (m_pFile == NULL)
{
return false;
}
m_bRunning = true;
return true;
}
bool CDownloader::stop()
{
clear();
m_bRunning = false;
return true;
}
size_t CDownloader::handleWrite( void *buffer, size_t size, size_t nmemb, void *userp )
{
CDownloader* pDownloader = (CDownloader*) userp;
if (pDownloader)
{
return pDownloader->onWrite(buffer, size, nmemb);
}
return 0;
}
size_t CDownloader::handleProgress( void *buffer, double dltotal, double dlnow, double ultotal, double ulnow )
{
CDownloader* pDownloader = (CDownloader*) buffer;
if (pDownloader)
{
pDownloader->onProgress(dltotal, dlnow);
}
return 0;
}
size_t CDownloader::onProgress( const double& dltotal, const double& dlnow )
{
TRACE("%.2f / %.2f (%.2g %%)\n", dlnow, dltotal, dlnow*100.0/dltotal);
return 0;
}
size_t CDownloader::onWrite( void *buffer, size_t size, size_t nmemb )
{
size_t return_size = fwrite(buffer, size, nmemb, m_pFile);
//std::cout << (char*) buffer << std::endl;
return return_size;
}
void CDownloader::onDownload()
{
// 执行下载
CURLcode return_code = CURLE_OK;
return_code = curl_easy_perform(m_pCurl);
// 关闭文件
if (m_pFile)
{
fclose(m_pFile);
m_pFile = NULL;
}
// 下载失败
if (return_code != CURLE_OK)
{
return;
}
// 获取状态码
int response_code = 0;
curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code != 200)
{
return;
}
}
使用示例:
CDownloader downloader;
downloader.start("http://xingke.onlinedown.net:82/down/QQ2013SP6.zip", "QQ2013SP6.zip");
downloader.run();
需要说明的是,这个类本身其实是运行于线程环境下的,因此,加入到多线程环境下,并非难事。扩展或者修改也并不是难得事情,比之WinInet的实现来说,libcurl的实现实在是简单得无话可说。
二、
[libcurl]_[初级]_[使用libcurl下载大文件]
场景:
1. 在Windows编程时, 下载http页面(html,xml)可以使用winhttp库,但是并不是很下载文件,因为会失败. 由此引出了WinINet库,无奈这个库的稳定性比较低,使用例子又少,
下载大文件时经常是不完整,可查找的资料很少或者是没有特殊情况的解决办法。
2. 我的原则是如果系统有自带的就用系统的,但是 WinINet 要掌握需要花不少时间. 时间因素考虑到了libcurl.
3. libcurl支持ftp,http等协议的文件读取,还能自动获取文件大小, 最重要的是不需要怎么修改就能稳定支持完整下载大文件,还能支持跨平台(Windows,MacOSX)。
参考编译后的curl.exe使用:
[plain] view plain copy
- curl.exe -O http://img.ptcms.csdn.net/article/201506/25/558bbe1baed6e.jpg
之前也有写libcurl的使用的其他场景:
[libcurl]_[C/C++]_[使用libcurl库做简单软件更新解决方案]
编译mingw库很容易,直接依赖windows本地库就行,要编译msvc版本的话需要进入 winbuild 目录,参考 BUILD.WINDOWS.txt 里的
[cpp] view plain copy
- nmake /f Makefile.vc mode=<static or dll> <options>
我用的配置
[cpp] view plain copy
- nmake /f Makefile.vc mode=dll VC=10 ENABLE_IDN=no
http_download_domain.h
[cpp] view plain copy
- #ifndef __HTTP_DOWNLOAD_DOMAIN
- #define __HTTP_DOWNLOAD_DOMAIN
- #include <string>
- #include "curl/curl.h"
- class HttpDownloadDomain
- {
- public:
- HttpDownloadDomain(bool* cancel);
- ~HttpDownloadDomain();
- bool DownloadFile(std::string url,std::wstring path);
- bool *cancel_;
- private:
- static size_t DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam);
- static int ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
- };
- #endif
http_download_domain.cpp
[cpp] view plain copy
- #include "stdafx.h"
- #include "http_download_domain.h"
- #include <iostream>
- HttpDownloadDomain::HttpDownloadDomain(bool* cancel)
- {
- cancel_ = cancel;
- }
- HttpDownloadDomain::~HttpDownloadDomain()
- {
- }
- size_t HttpDownloadDomain::DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam)
- {
- FILE* fp = (FILE*)pParam;
- size_t nWrite = fwrite(pBuffer, nSize, nMemByte, fp);
- return nWrite;
- }
- int HttpDownloadDomain::ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
- {
- HttpDownloadDomain* dd = (HttpDownloadDomain*)clientp;
- if ( dltotal > -0.1 && dltotal < 0.1 )
- {
- return 0;
- }
- int nPos = (int) ( (dlnow/dltotal)*100 );
- //通知进度条更新下载进度
- std::cout << "dltotal: " << (long)dltotal << " ---- dlnow:" << (long)dlnow << std::endl;
- if(*dd->cancel_)
- {
- //1. 返回非0值就会终止 curl_easy_perform 执行
- return -2;
- }
- return 0;
- }
- bool HttpDownloadDomain::DownloadFile(std::string URLADDR,std::wstring path)
- {
- //初始化curl,这个是必须的
- CURL *curl = curl_easy_init();
- curl_easy_setopt(curl, CURLOPT_URL, URLADDR.c_str());
- //设置接收数据的回调
- FILE* file = _wfopen(path.c_str(), L"wb");
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DownloadCallback);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA,file);
- curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, ProgressCallback);
- curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,this);
- CURLcode retcCode = curl_easy_perform(curl);
- const char* pError = curl_easy_strerror(retcCode);
- std::cout << "pError: " << pError << std::endl;
- fclose(file);
- //清理curl,和前面的初始化匹配
- curl_easy_cleanup(curl);
- return !retcCode;
- }
使用方式:
[cpp] view plain copy
- #include "stdafx.h"
- #include "http_download_domain.h"
- int _tmain(int argc, _TCHAR* argv[])
- {
- bool i = 0;
- HttpDownloadDomain hdd(&i);
- hdd.DownloadFile("http://img.ptcms.csdn.net/article/201506/25/558bbe1baed6e.jpg",L"C:\\Users\\apple\\Downloads\\558bbe1baed6e.jpg");
- system("pause");
- return 0;
- }
下载完整例子:
http://download.csdn.net/detail/infoworld/8840787