C++开源库之Curl

关于Curl库

curl 是一个利用URL语法在命令行方式下工作的文件传输工具。它支持很多协议:FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE 以及 LDAP。curl不但提供了一个可执行的工具库,还提供了供程序开发的libcurl库,该库使用c语言编写,支持跨平台,libcurl的下载地址点这里。下载的安装包里面有个Project文件夹,该目录下全是已经对用户提供的Visual Studio工程库,包括Visual Studio的各个版本,提供代码示例以及库的编译,而且还提供多种编译方式,包括静态库,动态库,调试版、发布版,所谓真是业界良心的。提供的版本列表如下所示:

C++开源库之Curl_第1张图片


编译安装

编译curl库很简单的,找到自己对应的VS目录,然后打开工程,选择所需要的版本即可编译。我使用的是VS2010的静态库版本,因此选择VC10目录->LIB Debug版本,然后编译,编译后生成libcurld.lib和对应的调试信息文件libcurld.pdb,这样我们开发调试的时候只需要把该库文件和curl库的头文件文件夹curl加到我们的工程里面就可以使用curl库给我们提供的功能了。不过需要注意的是,因为CURL的特殊性,需要预定义一些宏和添加特定的依赖库,如下所示:

// 需要定义的宏,要不然会提示找不到某些函数的定义
#define BUILDING_LIBCURL
//#define HTTP_ONLY

// 依赖库
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wldap32.lib")
#pragma comment(lib, "libcurld.lib")

主要函数列表

  • 全局初始化
    CURLcode curl_global_init(long flags);
    描述: 这个函数只能用一次(其实在调用curl_global_cleanup 函数后仍然可再用),如果这个函数在curl_easy_init函数调用时还没调用,它讲由libcurl库自动完成。   
    参数:flags
    CURL_GLOBAL_ALL         //初始化所有的可能的调用。     
    CURL_GLOBAL_SSL         //初始化支持 安全套接字层。     
    CURL_GLOBAL_WIN32       //初始化win32套接字库。     
    CURL_GLOBAL_NOTHING     //没有额外的初始化

  • 全局清理
    void curl_global_cleanup(void);
    描述:在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数。

  • 获取Curl版本库
    char *curl_version();
    描述: 打印当前libcurl库的版本。

  • 初始化curl会话
    CURL *curl_easy_init();
    描述: curl_easy_init用来初始化一个CURL的指针(有些像返回FILE类型的指针一样),相应的在调用结束时要用curl_easy_cleanup函数清理。一般curl_easy_init意味着一个会话的开始,它的返回值一般都用在easy系列的函数。
  • 清理cur会话
    void curl_easy_cleanup(CURL *handle);
    描述: 这个调用用来结束一个会话,与curl_easy_init配合着用。

    参数: CURL类型的指针。
  • 设置curl会话参数
    CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
    描述: 这个函数最重要了,几乎所有的curl程序都要频繁的使用它,用来设置参数。它告诉curl库,程序将有如何的行为,比如要查看一个网页的html代码等。
    参数handle:CURL类型的指针 
    参数option:各种CURLoption类型的选项。(都在curl.h库里有定义,man 也可以查看到)     
    参数parameter: 这个参数既可以是个函数的指针,也可以是某个对象的指针,也可以是个long型的变量,它用什么这取决于第二个参数。

  • 执行curl会话
    CURLcode curl_easy_perform(CURL *handle);
    描述:这个函数在初始化CURL类型的指针以及curl_easy_setopt完成后调用,就像字面的意思所说perform就像是个舞台,让我们设置的option运作起来,执行curl所设置的动作。
    参数: CURL类型的指针

代码示例(参 C++使用libcurl做HttpClient

一个使用curl封装Post和Get方法的类

#ifndef __MY_CURL_H__
#define __MY_CURL_H__

#define BUILDING_LIBCURL
//#define HTTP_ONLY

#include 

class CHttpClient
{
public:
	CHttpClient(void);
	~CHttpClient(void);

public:
	/**
	* @brief HTTP POST请求
	* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
	* @param strPost 输入参数,使用如下格式para1=val1¶2=val2&…
	* @param strResponse 输出参数,返回的内容
	* @return 返回是否Post成功
	*/
	int Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse);

	/**
	* @brief HTTP GET请求
	* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
	* @param strResponse 输出参数,返回的内容
	* @return 返回是否Post成功
	*/
	int Get(const std::string & strUrl, std::string & strResponse);

	/**
	* @brief HTTPS POST请求,无证书版本
	* @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
	* @param strPost 输入参数,使用如下格式para1=val1¶2=val2&…
	* @param strResponse 输出参数,返回的内容
	* @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
	* @return 返回是否Post成功
	*/
	int Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath = NULL);

	/**
	* @brief HTTPS GET请求,无证书版本
	* @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
	* @param strResponse 输出参数,返回的内容
	* @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
	* @return 返回是否Post成功
	*/
	int Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath = NULL);

public:
	void SetDebug(bool bDebug);

private:
	bool m_bDebug;
};

#endif

#include "my_curl.h"
#include "curl/curl.h"
#include 


#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wldap32.lib")
#pragma comment(lib, "libcurld.lib")

CHttpClient::CHttpClient(void) : 
m_bDebug(false)
{

}

CHttpClient::~CHttpClient(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)
{
	std::string* str = dynamic_cast((std::string *)lpVoid);
	if( NULL == str || NULL == buffer )
	{
		return -1;
	}

    char* pData = (char*)buffer;
    str->append(pData, size * nmemb);
	return nmemb;
}

int CHttpClient::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse)
{
	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, strPost.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);
	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 CHttpClient::Get(const std::string & strUrl, std::string & strResponse)
{
	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);
	/**
	* 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。
	* 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。
	*/
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	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 CHttpClient::Posts(const std::string & strUrl, const std::string & strPost, std::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, strPost.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 CHttpClient::Gets(const std::string & strUrl, std::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);
		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;
}

///

void CHttpClient::SetDebug(bool bDebug)
{
	m_bDebug = bDebug;
}
从上述代码可以看出,使用curl库主要分为四个步骤:init,setopt,perform和cleanup,其中setopt最重要,用来指定参数

你可能感兴趣的:(工具,c++,windows)