使用libcurl实现的下载器

本文介绍了一个使用libcurl库实现的下载器类,详细解释了如何通过设置选项、回调函数来完成HTTP、HTTPS、FTP等协议的下载操作。包括初始化、开始下载、停止下载、进度和写入回调等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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的实现实在是简单得无话可说。
资源下载链接为: https://pan.quark.cn/s/27aaeeaf622d 在优快云博客中,作者详细介绍了一种基于libcurl实现HTTP GET和POST请求的方法,并将这两种请求封装为http_get和http_post函数,使得调用过程极为简便,仅需一行代码即可完成相应的网络请求操作。 具体来说,作者首先介绍了如何在Visual Studio 2017环境下编译libcurl库。这包括从官网下载源码,运行buildconf.bat文件,以及使用VS2017的命令提示工具进行编译。编译时,用户可以根据需要选择静态库或动态链接库的生成方式,并指定目标平台(如x64或x86)以及调试或发布版本。编译完成后,生成的库文件位于builds文件夹下的include和lib文件夹中。 接着,作者说明了如何在C++工程中设置和使用这些库。这包括将include和lib文件夹拷贝到工程目录下,设置工程的字符集为多字节字符集,添加包含目录和库目录路径,定义预处理器宏(如CURL_STATICLIB等),以及在链接器中添加必要的依赖项(如libcurl_a.lib等)。 在源码部分,作者提供了封装好的http_get和http_post函数。这些函数的实现基于libcurl库,通过简单的调用即可完成GET或POST请求。例如,调用http_get("http://127.0.0.1:1234/hi")即可发送一个GET请求到指定的URL。此外,作者还提到了如何解决与Python服务器通信时可能出现的中文乱码问题。 通过这种方式,用户可以非常方便地在自己的C++项目中使用libcurl进行网络请求,而无需深入了解libcurl的复杂细节。更多详细信息和源码下载地址可以在博客文章中找到,文章链接为:libcurl POST GET 完整步骤与源码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值