小谈libcurl

之前使用socket来进行客户端和服务器的通信,必须自己构造HTTP头,HTTP体,非常麻烦,而且容易出错。后来使用了libcurl,真心觉得这是一个好东西。

下面是一个简单的封装类。

http_client.h

#ifndef __HTTP_CLIENT_H__
#define __HTTP_CLIENT_H__

#include <string>
#include <curl/curl.h>
/*
 *@Author LinuxPhilosopy
 *Date: 2013-04-28
 */
using namespace std;
class HttpClient
{
        public:
                HttpClient();
                ~HttpClient();
                /*
                 * connect_timeout_ms 连接超时时间,单位ms
                 * timeout 超时时间
                 * retry_times 重试时间
                 * dns_cache_timeout dns缓存时间
                 */
                int init(int connect_timeout_ms,int timeout,int retry_times,int dns_cache_timeout=60);
                /*
                 * function: POST
                 * url 请求的url
                 * data HTTP包体
                 * resp 响应的包体内容
                 * 0 成功 -1 失败
                 */
                int post_data(const string& url,const string& data,string& resp);
                /*
                 * function: GET
                 * url 请求的url
                 * resp 响应
                 * 0 成功 -1 失败
                 */
                int get_data(const string& url,string& resp);
                /*
                 * Debug
                 */
                void set_verbose(const int verbose);
                /*
                 *回调函数
                 */
                static size_t on_write_data(void * buffer, size_t size, size_t nmemb, string & resp);

        private:
                int _connect_timeout_ms;
                int _timeout;
                int _retry_times;
                int _dns_cache_timeout;
                int _verbose;
                CURL* _handler;
};
#endif

http_client.cpp

#include "http_client.h"

HttpClient::HttpClient()
{
}

HttpClient::~HttpClient()
{
        curl_easy_cleanup(_handler);
        curl_global_cleanup();
}

int HttpClient::init(const int connect_timeout_ms,const int timeout, const int retry_times, int dns_cache_timeout)
{
        _connect_timeout_ms=connect_timeout_ms;
        _timeout = _timeout;
        _retry_times = retry_times;
        _dns_cache_timeout = dns_cache_timeout;
        _verbose=0;

        CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
        if (code != CURLE_OK)
        {
            return -1;
        }
        _handler = curl_easy_init();
        if(!_handler)
        {
                return -1;
        }
        return 0;
}

size_t HttpClient::on_write_data(void * buffer, size_t size, size_t nmemb, string & resp)
{
        long len=size*nmemb;
        resp+=(char*)buffer;
        return len;
}

int HttpClient::post_data(const string & url, const string & data, string & resp)
{
        if( _handler)
        {
                 curl_easy_reset(_handler);
        }else
        {
                 _handler= curl_easy_init();
        }
        curl_easy_setopt(_handler,CURLOPT_URL,url.c_str());
        curl_easy_setopt(_handler,CURLOPT_POSTFIELDS,data.c_str());
        curl_easy_setopt(_handler,CURLOPT_POSTFIELDSIZE,data.length());
        curl_easy_setopt(_handler,CURLOPT_TIMEOUT,_timeout);
        curl_easy_setopt(_handler,CURLOPT_CONNECTTIMEOUT_MS,_connect_timeout_ms);
        curl_easy_setopt(_handler,CURLOPT_DNS_CACHE_TIMEOUT,_dns_cache_timeout);
        curl_easy_setopt(_handler,CURLOPT_NOSIGNAL,1);
        curl_easy_setopt(_handler,CURLOPT_WRITEFUNCTION,on_write_data);
        curl_easy_setopt(_handler,CURLOPT_WRITEDATA,&resp);
        if(_verbose==1)
        {
                curl_easy_setopt(_handler,CURLOPT_VERBOSE,1);
        }
        int i=0;
        CURLcode res;
        for(i=0;i<_retry_times;i++){
                res=curl_easy_perform(_handler);
                if( res == CURLE_OK)
                {
                        break;
                }
                resp="";
        }
        if(i==_retry_times)
                return -1;
        return 0;
}

int HttpClient::get_data(const string& url,string& resp)
{
        if( _handler)
        {
                 curl_easy_reset(_handler);
        }else
        {
                _handler= curl_easy_init();
        }
        curl_easy_setopt(_handler,CURLOPT_URL,url.c_str());
        curl_easy_setopt(_handler,CURLOPT_TIMEOUT,_timeout);
        curl_easy_setopt(_handler,CURLOPT_CONNECTTIMEOUT_MS,_connect_timeout_ms);
        curl_easy_setopt(_handler,CURLOPT_DNS_CACHE_TIMEOUT,_dns_cache_timeout);
        curl_easy_setopt(_handler,CURLOPT_NOSIGNAL,1);
        curl_easy_setopt(_handler,CURLOPT_WRITEFUNCTION,on_write_data);
        curl_easy_setopt(_handler,CURLOPT_WRITEDATA,&resp);
        if(_verbose==1)
        {
                curl_easy_setopt(_handler,CURLOPT_VERBOSE,1);
        }
        int i=0;
        CURLcode res;
        for(i=0;i<_retry_times;i++){
                res=curl_easy_perform(_handler);
                if( res == CURLE_OK)
                {
                        break;
                }
                resp="";
        }
        if(i==_retry_times)
                return -1;
        return 0;
}

void HttpClient::set_verbose(int verbose)
{
        if(verbose!=0)
                _verbose=1;
}

下面是测试demo.

main.cpp

#include "http_client.h"
#include <iostream>
using namespace std;

int main(int argc,char** argv)
{
        HttpClient _client;
        if(_client.init(2000,5,3)<0)
        {
                cout<<"init client failed."<<endl;
                return -1;
        }
        _client.set_verbose(1);
        string url="www.baidu.com";
        string resp;
        if(_client.get_data(url,resp)<0)
        {
                cout<<"curl error."<<endl;
                return -1;
        }
        cout<<"GET 响应:\n"<<resp<<endl;

        url="http://js.vnet.cn/ProvinceForDACS/services/ProvinceForDACS?wsdl";
        string data="<?xml version='1.0' encoding='UTF-8'?><soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' soap:encodingStyle='http://www.w3.org/2001/12/soap-encoding' ><soap:Body><dacs:speedUp xmlns:dacs='http://lccss.linkage.com'><spid>11002001</spid><serviceid>1100200199999998</serviceid><authenticator>fYRJhNKy15fEyzDyt/gq065s5PLe0+Yw</authenticator><starttime>1365749347617</starttime><userid>11009499085</userid><clientIP>114.221.84.35</clientIP><time>0</time><port>8999</port></dacs:speedUp></soap:Body></soap:Envelope>";
        resp="";
        if(_client.post_data(url,data,resp)<0)
        {
                cout<<"post curl error."<<endl;
                return -1;
        }
        cout<<"POST 响应:\n"<<resp<<endl;
        return 0;
}

运行结果:


POST请求中,因为这里是向Web Service提交请求,需要包含相应的请求头,数据包才会被服务器端正确解析。具体自己添加请求头,可以使用如下代码

 struct curl_slist* headers=NULL;
 headers=curl_slist_append(headers,"Content-Type:text/xml");
 curl_slist_append(headers,"Accept:text/xml");
 curl_slist_append(headers,"SOAPAction:''");
 curl_easy_setopt(handle,CURLOPT_HTTPHEADER,headers); 

最后记得释放headers

curl_slist_free_all(headers);

所以从这里也看出这个封装类不够灵活,如果需要自定义HTTP HEADERS,可以在get_data,post_data方法中添加个map参数。但是对于一般的需求这个HttpClient应该大体满足了。。。所以就没加上了。。。

最后,需要注意几点:

1.回调函数必须是类的静态成员函数。

2.如果使用到定时器(我们这里设置了连接超时时间和响应超时等),应设置CURLOPT_NOSIGNAL为1,防止如果主线程使用到sleep或wait,程序自动退出。。。

3.该封装类可以指定重试次数,也比较合理

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值