使用libcurl实现的下载器,取消下载

转载文章 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 == truereturn 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

  1. 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

  1. nmake /f Makefile.vc mode=<static or dll> <options>  


我用的配置

 

 

[cpp] view plain copy

  1. nmake /f Makefile.vc mode=dll VC=10 ENABLE_IDN=no  


http_download_domain.h

 

 

[cpp] view plain copy

  1. #ifndef __HTTP_DOWNLOAD_DOMAIN  
  2. #define __HTTP_DOWNLOAD_DOMAIN  
  3.   
  4. #include <string>  
  5. #include "curl/curl.h"  
  6.   
  7. class HttpDownloadDomain  
  8. {  
  9. public:  
  10.     HttpDownloadDomain(bool* cancel);  
  11.     ~HttpDownloadDomain();  
  12.     bool DownloadFile(std::string url,std::wstring path);  
  13.     bool *cancel_;  
  14.   
  15. private:  
  16.       
  17.     static size_t DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam);  
  18.     static int ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);  
  19.       
  20. };  
  21.   
  22. #endif  


http_download_domain.cpp

 

 

[cpp] view plain copy

  1. #include "stdafx.h"  
  2.   
  3. #include "http_download_domain.h"  
  4.   
  5. #include <iostream>  
  6.   
  7. HttpDownloadDomain::HttpDownloadDomain(bool* cancel)  
  8. {  
  9.     cancel_ = cancel;  
  10. }  
  11.   
  12. HttpDownloadDomain::~HttpDownloadDomain()  
  13. {  
  14. }  
  15.   
  16. size_t HttpDownloadDomain::DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam)    
  17. {    
  18.     FILE* fp = (FILE*)pParam;    
  19.     size_t nWrite = fwrite(pBuffer, nSize, nMemByte, fp);    
  20.       
  21.     return nWrite;    
  22. }    
  23.     
  24. int HttpDownloadDomain::ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)    
  25. {    
  26.     HttpDownloadDomain* dd = (HttpDownloadDomain*)clientp;  
  27.   
  28.     if ( dltotal > -0.1 && dltotal < 0.1 )    
  29.     {  
  30.         return 0;  
  31.     }  
  32.     int nPos = (int) ( (dlnow/dltotal)*100 );    
  33.     //通知进度条更新下载进度  
  34.     std::cout << "dltotal: " << (long)dltotal << " ---- dlnow:" << (long)dlnow << std::endl;  
  35.   
  36.     if(*dd->cancel_)  
  37.     {  
  38.         //1. 返回非0值就会终止 curl_easy_perform 执行  
  39.         return -2;  
  40.     }  
  41.     return 0;    
  42. }  
  43.   
  44. bool HttpDownloadDomain::DownloadFile(std::string URLADDR,std::wstring path)  
  45. {  
  46.     //初始化curl,这个是必须的    
  47.     CURL *curl = curl_easy_init();    
  48.     curl_easy_setopt(curl, CURLOPT_URL, URLADDR.c_str());    
  49.   
  50.     //设置接收数据的回调   
  51.     FILE* file = _wfopen(path.c_str(), L"wb");  
  52.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DownloadCallback);  
  53.     curl_easy_setopt(curl, CURLOPT_WRITEDATA,file);  
  54.     curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);    
  55.     curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);    
  56.     curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);    
  57.     curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, ProgressCallback);  
  58.     curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,this);  
  59.     CURLcode retcCode = curl_easy_perform(curl);  
  60.       
  61.   
  62.     const char* pError = curl_easy_strerror(retcCode);  
  63.     std::cout << "pError: " << pError << std::endl;  
  64.     fclose(file);  
  65.     //清理curl,和前面的初始化匹配    
  66.     curl_easy_cleanup(curl);  
  67.   
  68.     return !retcCode;  
  69. }  


使用方式:

 

 

[cpp] view plain copy

  1. #include "stdafx.h"  
  2.   
  3. #include "http_download_domain.h"  
  4.   
  5. int _tmain(int argc, _TCHAR* argv[])  
  6. {  
  7.     bool i = 0;  
  8.     HttpDownloadDomain hdd(&i);  
  9.     hdd.DownloadFile("http://img.ptcms.csdn.net/article/201506/25/558bbe1baed6e.jpg",L"C:\\Users\\apple\\Downloads\\558bbe1baed6e.jpg");  
  10.     system("pause");  
  11.     return 0;  
  12. }  

 

下载完整例子:

 

http://download.csdn.net/detail/infoworld/8840787

 

 

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libcurl提供了一些选项和回调函数,可以用于实现暂停和继续下载。具体来说,可以通过设置CURLOPT_WRITEFUNCTION选项和CURLOPT_WRITEDATA选项来控制接收到的数据的处理方式,然后在回调函数中添加暂停和继续下载的逻辑。 例如,可以设置一个全局变量或者结构体来控制下载的状态,并在回调函数中检查该变量的值来决定是否继续处理数据。当需要暂停下载时,将该变量的值设置为一个特定的标记,然后在回调函数中判断该标记是否已被设置。如果已经设置,就返回一个非零值,告诉libcurl停止传输数据,直到该变量被重新设置为其他值。当需要继续下载时,将该变量的值设置为其他值,再次调用curl_easy_perform()函数即可。 示例代码如下: ``` int transfer_paused = 0; FILE *fp = NULL; size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { // check if transfer is paused if (transfer_paused) { return CURL_WRITEFUNC_PAUSE; } // write received data to file fwrite(ptr, size, nmemb, fp); return size * nmemb; } // pause transfer transfer_paused = 1; // resume transfer transfer_paused = 0; curl_easy_perform(curl); ``` 在这个示例中,当transfer_paused变量被设置为1时,回调函数write_callback()会返回CURL_WRITEFUNC_PAUSE来暂停下载。当该变量被设置为0时,回调函数将继续将数据写入文件。可以根据需要在其他地方设置和清除该变量的值,并在下载暂停和继续时调用curl_easy_perform()函数。另外,需要在设置CURLOPT_WRITEFUNCTION选项和CURLOPT_WRITEDATA选项之前,打开或创建一个文件,并将文件指针传递给CURLOPT_WRITEDATA选项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值