c++ 利用libcurl实现文件断点续传

来源:互联网 发布:黄金投资软件 编辑:程序博客网 时间:2024/06/06 14:15

原文地址:http://blog.csdn.net/mfcing/article/details/50775164

/******************************************封装Libcurl下载库*author:Jelin*date:2016年2月24日*/#pragma once#include <curl/curl.h>#include <string>using std::string;class CLibcurlCallback{public:virtual void Progress(void* lpParam, double dTotal, double bLoaded) = 0;};enum LibcurlFlag{Lf_None = 0,Lf_Download,Lf_Post,Lf_Get,};class CLibcurl{public:CLibcurl(void);~CLibcurl(void);/*******************************************************************************封装类的外部调用接口*/bool SetPort(LONG port);//设置连接端口号bool SetTimeout(int nSecond);//设置执行超时(秒)bool SetConnectTimeout(int nSecond);//设置连接超时(秒)bool SetUserAgent(LPCSTR lpAgent);//设置用户代理bool SetResumeFrom(LONG lPos);//设置断点续传起始位置bool SetResumeFromLarge(LONGLONG llPos);//设置断点续传起始位置,针对大文件bool AddHeader(LPCSTR lpKey, LPCSTR lpValue);//添加自定义头void ClearHeaderList();//清理HTTP列表头bool SetCookie(LPCSTR lpCookie);//设置HTTP请求cookiebool SetCookieFile(LPCSTR lpFilePath);//设置HTTP请求cookie文件const char* GetError()const;//获取错误详细信息void SetCallback(CLibcurlCallback* pCallback, void* lpParam);//设置下载进度回调bool DownloadToFile(LPCSTR lpUrl, LPCSTR lpFile);//下载文件到磁盘bool Post(LPCSTR lpUrl, LPCSTR lpData);//Post 字符串数据bool Post(LPCSTR lpUrl, unsigned char* lpData, unsigned int nSize); //Post 字符串或者二进制数据bool Get(LPCSTR lpUrl);//Get 请求const string& GetRespons()const;//获取Post/Get请求返回数据const char*GetResponsPtr()const;//获取Post/Get请求返回数据protected:static size_tWriteCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam);static size_tHeaderCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam);static intProgressCallback(void *pParam, double dltotal, double dlnow, double ultotal, double ulnow);private:CURL*m_pCurl;LONGm_nPort;HANDLEm_hFile;CURLcode m_curlCode;stringm_strRespons;LibcurlFlag m_lfFlag;curl_slist *m_curlList;void*m_pCallbackParam;CLibcurlCallback*m_pCallback;};

#include "StdAfx.h"#include "Libcurl.h"#include <assert.h>#ifdef _DEBUG#pragma comment(lib, "libcurl/libcurld_SSL")#pragma comment(lib, "libcurl/libeay32.lib")#pragma comment(lib, "libcurl/ssleay32.lib")#else#pragma comment(lib, "libcurl//libcurl")#endif#pragma comment(lib, "ws2_32")#pragma comment(lib, "Iphlpapi")#pragma comment(lib, "Wldap32")CLibcurl::CLibcurl(void): m_pCurl(NULL), m_nPort(80), m_hFile(INVALID_HANDLE_VALUE), m_pCallback(NULL), m_pCallbackParam(NULL), m_curlCode(CURLE_OK), m_lfFlag(Lf_None), m_curlList(NULL){m_pCurl = curl_easy_init();curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, WriteCallback);curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, this);}CLibcurl::~CLibcurl(void){ClearHeaderList();curl_easy_cleanup(m_pCurl);if ( m_hFile != INVALID_HANDLE_VALUE ){CloseHandle(m_hFile);}}bool CLibcurl::SetPort( LONG port ){if ( port == m_nPort ) return true;m_nPort = port;m_curlCode = curl_easy_setopt(m_pCurl, CURLOPT_PORT, m_nPort);return CURLE_OK == m_curlCode;}bool CLibcurl::SetTimeout( int nSecond ){if ( nSecond<0 )return false;m_curlCode = curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT, nSecond);return CURLE_OK == m_curlCode;}bool CLibcurl::SetConnectTimeout( int nSecond ){if ( nSecond<0 )return false;m_curlCode = curl_easy_setopt(m_pCurl, CURLOPT_CONNECTTIMEOUT, nSecond);return CURLE_OK == m_curlCode;}bool CLibcurl::SetUserAgent( LPCSTR lpAgent ){if ( NULL == lpAgent )return false;int nLen = strlen(lpAgent);if ( nLen == 0 )return false;m_curlCode = curl_easy_setopt(m_pCurl, CURLOPT_USERAGENT, lpAgent);return CURLE_OK == m_curlCode;}bool CLibcurl::SetResumeFrom( LONG lPos ){if ( lPos<0 )return false;m_curlCode = curl_easy_setopt(m_pCurl, CURLOPT_RESUME_FROM, lPos);return CURLE_OK == m_curlCode;}bool CLibcurl::SetResumeFromLarge( LONGLONG llPos ){if ( llPos<0 )return false;m_curlCode = curl_easy_setopt(m_pCurl, CURLOPT_RESUME_FROM_LARGE, llPos);return CURLE_OK == m_curlCode;}bool CLibcurl::AddHeader( LPCSTR lpKey, LPCSTR lpValue ){assert(lpKey!=NULL && lpValue!=NULL);int nLen1 = strlen(lpKey), nLen2 = strlen(lpValue);assert(nLen1>0 && nLen2>0);string strHeader(lpKey);strHeader.append(": ");strHeader.append(lpValue);m_curlList = curl_slist_append(m_curlList, strHeader.c_str());m_curlCode = curl_easy_setopt(m_pCurl, CURLOPT_HTTPHEADER, m_curlList);return CURLE_OK == m_curlCode;}void CLibcurl::ClearHeaderList(){if ( m_curlList ){curl_slist_free_all(m_curlList);m_curlList = NULL;}}bool CLibcurl::SetCookie( LPCSTR lpCookie ){assert(lpCookie!=NULL);m_curlCode = curl_easy_setopt(m_pCurl, CURLOPT_COOKIE, lpCookie);return CURLE_OK == m_curlCode;}bool CLibcurl::SetCookieFile( LPCSTR lpFilePath ){assert(lpFilePath!=NULL);m_curlCode = curl_easy_setopt(m_pCurl, CURLOPT_COOKIEFILE, lpFilePath);return CURLE_OK == m_curlCode;}const char* CLibcurl::GetError() const{return curl_easy_strerror(m_curlCode);}void CLibcurl::SetCallback( CLibcurlCallback* pCallback, void* lpParam ){m_pCallbackParam = lpParam;m_pCallback = pCallback;}bool CLibcurl::DownloadToFile( LPCSTR lpUrl, LPCSTR lpFile ){CURLcode code = curl_easy_setopt(m_pCurl, CURLOPT_URL, lpUrl);DeleteFileA(lpFile);m_hFile = CreateFileA(lpFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if ( INVALID_HANDLE_VALUE == m_hFile ){return FALSE;}curl_easy_setopt(m_pCurl, CURLOPT_NOPROGRESS, 0);curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSFUNCTION, ProgressCallback);curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSDATA, this);m_lfFlag = Lf_Download;//开始执行请求m_curlCode = curl_easy_perform(m_pCurl);return CURLE_OK == m_curlCode;}bool CLibcurl::Post( LPCSTR lpUrl, LPCSTR lpData ){assert(lpData!=NULL);curl_easy_setopt(m_pCurl, CURLOPT_POST, 1);curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, lpData);//curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDSIZE, lpData);curl_easy_setopt(m_pCurl, CURLOPT_URL, lpUrl);m_lfFlag = Lf_Post;m_strRespons.clear();m_curlCode = curl_easy_perform(m_pCurl);return CURLE_OK == m_curlCode;}bool CLibcurl::Post( LPCSTR lpUrl, unsigned char* lpData, unsigned int nSize ){assert(lpData!=NULL && nSize>0);curl_easy_setopt(m_pCurl, CURLOPT_POST, 1);curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, lpData);curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDSIZE, nSize);curl_easy_setopt(m_pCurl, CURLOPT_URL, lpUrl);m_lfFlag = Lf_Post;m_strRespons.clear();m_curlCode = curl_easy_perform(m_pCurl);return CURLE_OK == m_curlCode;}bool CLibcurl::Get( LPCSTR lpUrl ){assert(lpUrl!=NULL);curl_easy_setopt(m_pCurl, CURLOPT_HTTPGET, 1);curl_easy_setopt(m_pCurl, CURLOPT_URL, lpUrl);curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1);//支持重定向curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, 0L);curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, 0L);m_lfFlag = Lf_Get;m_strRespons.clear();m_curlCode = curl_easy_perform(m_pCurl);return CURLE_OK == m_curlCode;}const string& CLibcurl::GetRespons() const{return m_strRespons;}const char* CLibcurl::GetResponsPtr() const{return m_strRespons.c_str();}size_t CLibcurl::WriteCallback( void* pBuffer, size_t nSize, size_t nMemByte, void* pParam ){//把下载到的数据以追加的方式写入文件(一定要有a,否则前面写入的内容就会被覆盖了)CLibcurl* pThis = (CLibcurl*)pParam;DWORD dwWritten = 0;switch( pThis->m_lfFlag ){case Lf_Download://下载{if ( pThis->m_hFile == INVALID_HANDLE_VALUE )return 0;if ( !WriteFile(pThis->m_hFile, pBuffer, nSize*nMemByte, &dwWritten, NULL) )return 0;}break;case Lf_Post://Post数据case Lf_Get://Get数据{pThis->m_strRespons.append((const char*)pBuffer, nSize*nMemByte);dwWritten = nSize*nMemByte;}break;case Lf_None://未定义break;}return dwWritten;}size_t CLibcurl::HeaderCallback( void* pBuffer, size_t nSize, size_t nMemByte, void* pParam ){CLibcurl* pThis = (CLibcurl*)pParam;return 0;}int CLibcurl::ProgressCallback( void *pParam, double dltotal, double dlnow, double ultotal, double ulnow ){CLibcurl* pThis = (CLibcurl*)pParam;if ( pThis->m_pCallback ){pThis->m_pCallback->Progress(pThis->m_pCallbackParam, dltotal, dlnow);}return 0;}
我对代码的风格比较敏感,写代码必须要整齐干净,容易阅读。(PS:我的注释也是很整齐的,到了这里都乱了,CSDN的网页编辑器!)


封装的目的是让Libcurl更容易使用,使用了C++包装了一系列C函数,方便我们直接设置一些属性,调用方法,获取返回数据和错误信息等。

使用

下面代码介绍了使用封装库进行下载、Get请求和Post请求

// LibcurlLoad.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "Libcurl.h"class CLibcurlCallbackEx: public CLibcurlCallback{public:virtual void Progress(void* lpParam, double dTotal, double dLoaded){if ( dTotal == 0.0 ) return ;double bPercent = (dLoaded/dTotal)*100;printf("下载进度:%0.2lf%%\n", bPercent);}};void DownloadTest();void PostTest();void GetTest();int _tmain(int argc, _TCHAR* argv[]){//DownloadTest();//PostTest();GetTest();return 0;}void DownloadTest(){const char* pUrl = "http://download.*******.com/software/1.2.3.3639/32//Package";CLibcurl libcurl;CLibcurlCallbackEx cb;libcurl.SetUserAgent("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36");libcurl.SetConnectTimeout(2);libcurl.SetResumeFrom(2);libcurl.SetCallback(&cb, NULL);libcurl.DownloadToFile(pUrl, "c:\\test.zip");}void PostTest(){CLibcurl libcurl;libcurl.SetUserAgent("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36");libcurl.SetPort(80);libcurl.SetConnectTimeout(2);libcurl.AddHeader("name", "Jelin");libcurl.AddHeader("sex", "man");libcurl.SetCookieFile("c:\\cookie");char* pData = "maintype=10001&subtype=100&appver=2.5.19.3753&sysver=Microsoft Windows 7&applist=100:15,200:2&sign=2553d888bc922275eca2fc539a5f0c1b";libcurl.Post("http://interface.***********.com/v2/stat/index/jingpin", pData);string strRet = libcurl.GetRespons();}void GetTest(){CLibcurl libcurl;libcurl.SetUserAgent("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36");libcurl.Get("https://www.baidu.com");const char* pHtml = libcurl.GetResponsPtr();const char* pError = libcurl.GetError();}


如果你想知道下载进度,请继承CLibcurlCallback,在虚函数中实现下就可以了。
0 0
原创粉丝点击