1. 程式人生 > >使用libcurl實現的下載器,取消下載

使用libcurl實現的下載器,取消下載

轉載文章 http://blog.csdn.net/robertbaker/article/details/43703907

轉載文章   http://blog.csdn.net/infoworld/article/details/46646933

謝謝版主

一、使用libcurl實現的下載器


標頭檔案:

/**********************************************************************
* 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:
    
/// 執行緒入口函式
virtualbool run();

    
/// 啟動下載
virtualbool start(const std::string& strUrl, const std::string& strLocalFile);

    
/// 停止下載
virtualbool 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(constdouble& dltotal, constdouble& 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();
    
returntrue;
}


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()) returnfalse;

    
if (m_bRunning ==truereturntrue;

    clear();

    m_strDownloadUrl    
= strUrl;
    m_strLocalFilePath    
= strLocalFile;

    
// 初始化libcurl
    m_pCurl = curl_easy_init();
    
if (m_pCurl == NULL)
    
{
        
returnfalse;
    }


    
// 設定libcurl的選項
    setOption();

    
// 建立檔案
    m_pFile = fopen(m_strLocalFilePath.c_str(), "wb");
    
if (m_pFile == NULL)
    
{
        
returnfalse;
    }


    m_bRunning 
=true;

    
returntrue;
}


bool CDownloader::stop()
{
    clear();

    m_bRunning 
=false;

    
returntrue;
}


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);
    }

    return0;
}


size_t CDownloader::handleProgress( 
void*buffer, double dltotal, double dlnow, double ultotal, double ulnow )
{
    CDownloader
* pDownloader = (CDownloader*) buffer;
    
if (pDownloader)
    
{
        pDownloader
->onProgress(dltotal, dlnow);
    }

    return0;
}


size_t CDownloader::onProgress( 
constdouble& dltotal, constdouble& dlnow )
{
    TRACE(
"%.2f / %.2f (%.2g %%)\n", dlnow, dltotal, dlnow*100.0/dltotal);
    
return0;
}


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的實現實在是簡單得無話可說。

 二、

場景:

1. 在Windows程式設計時, 下載http頁面(html,xml)可以使用winhttp庫,但是並不是很下載檔案,因為會失敗. 由此引出了WinINet庫,無奈這個庫的穩定性比較低,使用例子又少,

下載大檔案時經常是不完整,可查詢的資料很少或者是沒有特殊情況的解決辦法。

2. 我的原則是如果系統有自帶的就用系統的,但是 WinINet 要掌握需要花不少時間. 時間因素考慮到了libcurl.

3. libcurl支援ftp,http等協議的檔案讀取,還能自動獲取檔案大小, 最重要的是不需要怎麼修改就能穩定支援完整下載大檔案,還能支援跨平臺(Windows,MacOSX)。

參考編譯後的curl.exe使用:

  1. curl.exe -O http://img.ptcms.csdn.net/article/201506/25/558bbe1baed6e.jpg  


之前也有