頭檔案:
/**********************************************************************
* 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);
/// 線程入口函數
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);
size_t onWrite(void *buffer, size_t size, size_t nmemb);
size_t onProgress(const double& dltotal, const double& dlnow);
/// 下載下傳回調
void onDownload();
/// 設定libcurl選項
void setOption();
/// 清除資料
void clear();
CURL* m_pCurl; ///< libcurl句柄
FILE* m_pFile; ///< 檔案指針
bool m_bRunning; ///< 運作标志
std::string m_strDownloadUrl; ///< 下載下傳連結
std::string m_strLocalFilePath; ///< 本地檔案路徑
};
#endif
實作檔案:
* 檔案名稱: Downloader_LibCurl.cpp
#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)
m_bRunning = true;
bool CDownloader::stop()
m_bRunning = false;
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;
pDownloader->onProgress(dltotal, dlnow);
size_t CDownloader::onProgress( const double& dltotal, const double& dlnow )
TRACE("%.2f / %.2f (%.2g %%)\n", dlnow, dltotal, dlnow*100.0/dltotal);
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 (return_code != CURLE_OK)
return;
// 擷取狀态碼
int response_code = 0;
curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code != 200)
使用示例:
CDownloader downloader;
downloader.start("http://xingke.onlinedown.net:82/down/QQ2013SP6.zip", "QQ2013SP6.zip");
downloader.run();
需要說明的是,這個類本身其實是運作于線程環境下的,是以,加入到多線程環境下,并非難事。擴充或者修改也并不是難得事情,比之WinInet的實作來說,libcurl的實作實在是簡單得無話可說。