C++ 基于libcurl的http客户端

当使用C++想要实现HTTP客户端时,目前通用的做法就是使用libcurl。本文主要分享的是一个基于libcurl的HTTP封装类,其功能包括:同步的(HTTP/HTTPS)GET、POST请求,以及文件下载和进度报告。

头文件代码:

#ifndef __BASE_EASY_CURL_H__
#define __BASE_EASY_CURL_H__
#include <Windows.h>
#include <string>
#include <functional>
using std::string;
//
class IProgressCallback
{
public:
	virtual bool OnProgressCallback(int nValue) = 0;
};

//
class EasyCurl
{
public:
	EasyCurl(void);
	~EasyCurl(void);
	typedef std::tr1::function<void(int)>  ProgressFunction;

public:

	/// @brief		HTTP POST请求
	/// @param[in]	strUrl 输入参数,请求的Url地址,如:https://www.baidu.com
	/// @param[in]	strParam 输入参数,使用格式"name=kandy&pwd=1234"
	/// @param[out]	strResponse 输出参数,返回的内容
	/// @param[in]	pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
	///	@remark		返回是否Post成功
	///	@return		CURLE_OK,成功!其余失败
	int http_post(const string & strUrl, const string & strParam, string & strResponse, const char * pCaPath = NULL);

	/// @brief		HTTPS GET请求
	/// @param[in]	strUrl 输入参数,请求的Url地址,如:https://www.baidu.com
	/// @param[out]	strResponse 输出参数,返回的内容
	/// @param[in]	pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
	///	@remark		返回是否Post成功
	///	@return		CURLE_OK,成功!其余失败
	int http_get(const string & strUrl, string & strResponse, const char * pCaPath = NULL);

	/// @brief		文件下载
	/// @param[in]	url : 要下载文件的url地址
	/// @param[in]	outfilename : 下载文件指定的文件名
	///	@remark		
	///	@return		返回0代表成功
	int download_file(const string & strUrl, const string & strFile);

	/// @brief		进度报告处理
	/// @param[in]	func : 函数地址
	///	@remark		
	///	@return		void
	void set_progress_function(ProgressFunction func);

	/// @brief		进度报告处理
	/// @param[in]	pCallback : 传入的对象
	///	@remark		使用的类继承于IProgressCallback
	///	@return		void
	void set_progress_callback(IProgressCallback *pCallback);
	//	
public:
	void SetDebug(bool bDebug);

protected:
	static int progress_callback(void *pParam, double dltotal, double dlnow, double ultotal, double ulnow);

private:
	bool m_bDebug;
	ProgressFunction	m_updateProgress;
	IProgressCallback	*m_pHttpCallback;
};

#endif//__BASE_EASY_CURL_H__


实现代码:

#include "EasyCurl.h"
#include "curl.h"

//#ifdef _DEBUG
//#pragma comment(lib,"libcurl_d.lib")
//#else
//#pragma comment(lib,"libcurl.lib")
//#endif

EasyCurl::EasyCurl(void) 
: m_bDebug(false)
{

}

EasyCurl::~EasyCurl(void)
{

}
//
static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)
{
	if(itype == CURLINFO_TEXT)
	{
		printf("[TEXT]%s\n", pData);
	}
	else if(itype == CURLINFO_HEADER_IN)
	{
		printf("[HEADER_IN]%s\n", pData);
	}
	else if(itype == CURLINFO_HEADER_OUT)
	{
		printf("[HEADER_OUT]%s\n", pData);
	}
	else if(itype == CURLINFO_DATA_IN)
	{
		printf("[DATA_IN]%s\n", pData);
	}
	else if(itype == CURLINFO_DATA_OUT)
	{
		printf("[DATA_OUT]%s\n", pData);
	}
	return 0;
}

static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
	string* str = dynamic_cast<string*>((string *)lpVoid);
	if( NULL == str || NULL == buffer )
	{
		return -1;
	}

    char* pData = (char*)buffer;
    str->append(pData, size * nmemb);
	return nmemb;
}
/*  libcurl write callback function */
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) 
{
	size_t written = fwrite(ptr, size, nmemb, stream);
	return written;

	//在这里可以把下载到的数据以追加的方式写入文件
	//FILE* fp = NULL;
	//fopen_s(&fp, "c:\\test.dat", "ab+");//一定要有a, 否则前面写入的内容就会被覆盖了
	//size_t nWrite = fwrite(ptr, nSize, nmemb, fp);
	//fclose(fp);
	//return nWrite;
}

//
int EasyCurl::progress_callback(void *pParam, double dltotal, double dlnow, double ultotal, double ulnow)
{
	EasyCurl* pThis = (EasyCurl*)pParam;
	int nPos = (int)((dlnow / dltotal) * 100);
	//
	if (pThis->m_pHttpCallback)
	{
		pThis->m_pHttpCallback->OnProgressCallback(nPos);
	}
	if (pThis->m_updateProgress)
	{
		pThis->m_updateProgress(nPos);
	}
	return 0;
}
//
int EasyCurl::http_post(const string & strUrl, const string & strParam, string & strResponse, const char * pCaPath)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if(NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	if(m_bDebug)
	{
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
	}
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_POST, 1);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strParam.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	if(NULL == pCaPath)
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
	}
	else
	{
		//缺省情况就是PEM,所以无需设置,另外支持DER
		//curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
		curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
	}
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}
//
int EasyCurl::http_get(const string & strUrl, string & strResponse, const char * pCaPath)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if(NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	if(m_bDebug)
	{
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
	}
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	if(NULL == pCaPath)
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);//设定为不验证证书和HOST
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
	}
	else
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
		curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
	}
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}
//
int EasyCurl::download_file(const string & strUrl, const string & strFile)
{
	FILE *fp;
	//调用curl_easy_init()函数得到 easy interface型指针
	CURL *curl = curl_easy_init();
	if (curl)
	{
		fopen_s(&fp, strFile.c_str(), "wb");

		CURLcode res = curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
		if (res != CURLE_OK)
		{
			fclose(fp);
			curl_easy_cleanup(curl);
			return -1;
		}

		res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
		if (res != CURLE_OK)
		{
			fclose(fp);
			curl_easy_cleanup(curl);
			return -1;
		}

		res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
		if (res != CURLE_OK)
		{
			fclose(fp);
			curl_easy_cleanup(curl);
			return -1;
		}
		curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);		
		curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);//设置进度回调函数
		curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this);
		//开始执行请求
		res = curl_easy_perform(curl);
		fclose(fp);
		/* Check for errors */
		if (res != CURLE_OK)
		{
			curl_easy_cleanup(curl);
			return -1;
		}
		curl_easy_cleanup(curl);//调用curl_easy_cleanup()释放内存
	}

	return 0;
}
//
void EasyCurl::set_progress_function(ProgressFunction func)
{
	m_updateProgress = func;
}
//
void EasyCurl::set_progress_callback(IProgressCallback *pCallback)
{ 
	m_pHttpCallback = pCallback; 
}
//
void EasyCurl::SetDebug(bool bDebug)
{
	m_bDebug = bDebug;
}

 

 

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hellokandy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值