curl 是一个利用URL语法在命令行方式下工作的文件传输工具。它支持很多协议:FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE 以及 LDAP。curl不但提供了一个可执行的工具库,还提供了供程序开发的libcurl库,该库使用c语言编写,支持跨平台,libcurl的下载地址点这里。下载的安装包里面有个Project文件夹,该目录下全是已经对用户提供的Visual Studio工程库,包括Visual Studio的各个版本,提供代码示例以及库的编译,而且还提供多种编译方式,包括静态库,动态库,调试版、发布版,所谓真是业界良心的。提供的版本列表如下所示:
编译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库自动完成。 void curl_global_cleanup(void);
描述:在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数。char *curl_version();
描述: 打印当前libcurl库的版本。CURL *curl_easy_init();
描述: curl_easy_init用来初始化一个CURL的指针(有些像返回FILE类型的指针一样),相应的在调用结束时要用curl_easy_cleanup函数清理。一般curl_easy_init意味着一个会话的开始,它的返回值一般都用在easy系列的函数。void curl_easy_cleanup(CURL *handle);
描述: 这个调用用来结束一个会话,与curl_easy_init配合着用。CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
描述: 这个函数最重要了,几乎所有的curl程序都要频繁的使用它,用来设置参数。它告诉curl库,程序将有如何的行为,比如要查看一个网页的html代码等。CURLcode curl_easy_perform(CURL *handle);
描述:这个函数在初始化CURL类型的指针以及curl_easy_setopt完成后调用,就像字面的意思所说perform就像是个舞台,让我们设置的option运作起来,执行curl所设置的动作。一个使用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最重要,用来指定参数