小谈libcurl

本文介绍了一个使用libcurl实现的HTTP客户端封装类,通过该类可以简化POST和GET请求的操作,并且提供了超时设置、重试机制等功能。实例展示了如何使用此封装类进行网络请求及获取响应。

之前使用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.该封装类可以指定重试次数,也比较合理

### libcurl FTP Upload File Size Limitations and Considerations When using `libcurl` for FTP uploads, several factors influence the maximum file size that can be transferred successfully. These constraints arise not only from `libcurl` itself but also depend heavily on server configurations and network conditions. #### Server-Side Constraints FTP servers may impose limits on the size of files they accept. Administrators configure these restrictions based on storage capacity, policy requirements, or performance optimization needs[^1]. Therefore, before initiating large transfers, it is advisable to consult documentation specific to the target FTP server regarding any imposed file-size limitations. #### Network Conditions Network stability plays a critical role during large file transmissions. Unstable connections increase the likelihood of interrupted transfers, which could lead to incomplete uploads. While `libcurl` provides mechanisms such as resuming partial downloads/uploads (`CURLOPT_RESUME_FROM_LARGE`) to mitigate this issue, ensuring reliable connectivity remains paramount. #### Client Configuration Options To manage large file uploads effectively when utilizing `libcurl`, consider configuring options like: - **Timeout Settings**: Adjusting timeout parameters (`CURLOPT_TIMEOUT_MS`, `CURLOPT_CONNECTTIMEOUT_MS`) ensures sufficient time for operations without premature termination due to extended processing times associated with larger datasets. - **Progress Callbacks**: Implement progress callbacks (`CURLOPT_XFERINFOFUNCTION`) to monitor transfer status closely and respond appropriately should issues arise mid-transfer. Below demonstrates how one might set up an environment suitable for handling sizable FTP uploads via `libcurl`. ```c CURL *curl; CURLcode res; struct curl_slist *headerlist = NULL; /* Initialize CURL */ curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(curl) { /* Set URL */ curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/path/to/file"); /* Specify local file path */ FILE *fp = fopen("/path/to/localfile", "rb"); if (!fp) perror("fopen"), exit(1); /* Enable uploading mode */ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); /* Provide pointer to data source */ curl_easy_setopt(curl, CURLOPT_READDATA, fp); /* Define custom headers if necessary */ headerlist = curl_slist_append(headerlist, "Content-Type: application/octet-stream"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); /* Configure timeouts */ curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 300000); // Five minutes curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 60000); // One minute /* Perform operation */ res = curl_easy_perform(curl); /* Cleanup resources */ fclose(fp); curl_slist_free_all(headerlist); curl_easy_cleanup(curl); } curl_global_cleanup(); ``` --related questions-- 1. How does enabling passive mode affect FTP upload speeds? 2. What measures can prevent corruption while transferring very large files over FTP? 3. Can compression improve efficiency when sending big files through FTP? 4. Is there support within libcurl for parallel multipart uploads?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值