curl的简单封装(c版本)

curl的简单封装(c版本)


curl的基本功能实现

(1). get , post , put, delete 发送数据
(2). 上传文件
(3). 下载文件



curl代码实现

(1). curl_global_init和curl_global_cleanup 只能使用一次, 通过一个静态成员变量加以限制
(2). get, post, put, delete, 上传文件, 下载文件的一些公用操作进行封装
(3). curl的封装,这里针对http


/*
* manager_curl.h
*/

/*
    * curl的封装,有以下操作:
    * 1.发送信息:get、post、put、delete
    * 2.上传文件处理
    * 3.下载文件

*/

#ifndef CLUSTER_CURL_H_
#define CLUSTER_CURL_H_

#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <stdbool.h>

#define  EPRINT  printf
#define  DPRINT  printf

/*
    * 宏定义curl个参数大小
*/
#define MAX_IP_LEN        (32)             //ip地址最大长度
#define MAX_URL_PATH_LEN  (128)            //url路径最大长度
#define MAX_USER_LEN      (64)             //用户名最大长度
#define MAX_PWD_LEN       (64)             //验证密码最大长度

#define MAX_URL_LEN       (168)            //url最大长度
#define MAX_REC_LEN       (20480)          //返回数据最大长度
#define MAX_TEMP_LEN      (128)            //临时变量最大长度

/*
    * 宏定义发送信息方法
*/
#define METHOD_GET         0                //0为GET方法
#define METHOD_POST        1                //1为POST方法
#define METHOD_PUT         2                //2为PUT方法
#define METHOD_DELETE      3                //3为DELETE方法

/*
    * 宏定义数据格式
*/
#define FORMAT_DEFAULT     0                //0为默认数据格式
#define FORMAT_XML         1                //1为xml数据格式
#define FORMAT_JSON        2                //2为json数据格式


/*
    * 宏定义超时时间
*/
#define C_CONNECT_DEFAULT_TIMEOUT  10  //连接最长时间
#define C_DEFAULT_TIMEOUT          600 //传输最长时间



/*
    * CLUSTER_CURL
    * 0表示成功, -1表示失败
*/

/*
    * curl结构体,包含相关参数
*/
typedef struct st_curl_params
{
    char ip[MAX_IP_LEN];                    //curl请求的ip
    char url_path[MAX_URL_PATH_LEN];        //url路径
    int  port;                              //curl请求ip的端口
    char user[MAX_USER_LEN];                //需要对方验证时使用,请求对方需要的用户名
    char pwd[MAX_PWD_LEN];                  //需要对方验证时使用,请求对方需要的密码
    int  format;                            //传送数据格式
    int  connect_timeout;                   //连接超时
    int  timeout;                           //传输最长时间
}st_curl_params;

/*
    * 返回数据结构体,包含相关参数
*/
typedef struct st_curl_rec
{
    char rec[MAX_REC_LEN];                  //curl返回数据数组空间大小,最大为10kb
    int  len;                               //curl实际返回数据大小
}st_curl_rec;

/*
    * 外部使用接口
*/

/*
    * 进行所有CURL开始之前,全局变量初始化,放在主线程中
*/
extern int curl_global_init_resource();

/*
    * 进行所有CURL结束之前,全局资源释放,放在主线程中
*/
extern int curl_global_cleanup_resource();

/*
    * 进行单个线程CURL简单资源进行初始化
*/
extern CURL* curl_init_resource();

/*
    * 进行单个线程CURL简单资源进行释放
*/
extern int curl_release_resource(CURL* curl);

/*
    * curl参数初始化
*/
extern int curl_init_params(st_curl_params* curl_params,
                            const char* ip,
                            const char* url_path,
                            const int port,
                            const char* user,
                            const char* pwd,
                            const int format);

/*
    * 设置发送路径
*/
extern void set_url_path(st_curl_params* curl_params, char* url_path);

/*
    * 设置连接超时
*/
extern void set_connect_timeout(st_curl_params* curl_params, int connect_timeout);

/*
    * 设置传输超时
*/
extern void set_timeout(st_curl_params* curl_params, int timeout);

/*
    * 发送消息发送方式
*/
extern int send_msg(CURL* curl,
                    st_curl_params* curl_params,
                    const char* msg,
                    const int method,
                    st_curl_rec* curl_rec);

/*
    * 下载文件
*/
extern int download_file(CURL* curl, st_curl_params* curl_params, const char* filename);

/*
    * 从文件中读取内容post出去
*/
extern int upload_file_content(CURL* curl,
                               st_curl_params* curl_params,
                               const char* filename,
                               st_curl_rec* curl_rec);

/*
    * 上传文件
*/
extern int upload_file(CURL* curl,
                       st_curl_params* curl_params,
                       const char* file_fullname,
                       st_curl_rec* curl_rec);



#endif     //CLUSTER_CURL.h



/*
* manager_curl.c
*/
/*
    * curl的封装的具体实现,有以下操作:
    * 1.发送信息:get、post、put、delete
    * 2.上传文件处理
    * 3.下载文件

*/

#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include "cluster_curl.h"


static bool s_global_init_status = 0;        //判断是否已进行全局初始化,0表示未初始化,1表示已经初始化


/*
    * 回调函数,处理返回的数据
    * 参数1:缓存存放
    * 参数2:缓存块数
    * 参数3:缓存每块大小
    * 参数4:WRITEDATA对应的数据流
    * 返回值,数据所占字节数
*/
static size_t http_data_writer(void* buffer, size_t size, size_t nmemb, void* content)
{
    long totalSize = size*nmemb;
    st_curl_rec* p_rec = (st_curl_rec*)content;

    if((NULL != buffer) && (totalSize < (sizeof(p_rec->rec) - p_rec->len)))
    {
        memcpy((char*)(p_rec->rec + p_rec->len), (char*)buffer, totalSize);
        p_rec->len = p_rec->len + totalSize;
        return totalSize;
    }
    else
    {
        EPRINT("http_data_writer data error(%d) \n", errno);
        return 0;
    }

}


/*
    * 回调函数,上传文件处理,读文件
    * 参数1:缓存存放
    * 参数2:缓存块数
    * 参数3:缓存每块大小
    * 参数4:READDATA对应的数据流
    * 返回值,数据所占字节数
*/
static size_t http_read_file(void* buffer, size_t size, size_t nmemb, void* file)
{
    return fread(buffer, size, nmemb, (FILE *)file);
}


/*
    * 回调函数,下载文件处理,写文件
    * 参数1:缓存存放
    * 参数2:缓存块数
    * 参数3:缓存每块大小
    * 参数4:WRITEDATA对应的数据流
    * 返回值,数据所占字节数
*/
static size_t http_write_file(void* buffer, size_t size, size_t nmemb, void* file)
{
    return fwrite(buffer, size, nmemb, (FILE *)file);
}


/*
    * 进行单个线程CURL简单资源进行初始化
    * 返回值:curl资源的指针
*/
CURL* curl_init_resource()
{
    return curl_easy_init();
}


/*
    * 进行单个线程CURL简单资源进行释放
    * 参数1:curl指针,通过此指针进行相关资源释放
    * 返回值为int, 0表示成功,其他表示失败
*/
int curl_release_resource(CURL* curl)
{
    if(NULL == curl)
    {
        EPRINT("rurl_release_resource curl ptr is null \n");
        return -1;       //CURL指针为NULL
    }
    curl_easy_cleanup(curl);
    curl = NULL;

    return 0;
}


/*
    * 宏定义数据格式字符串
*/
//XML格式
#define  XML_FORMAT_STRING        "Content-Type: application/xml;charset=UTF-8"
//JSON格式
#define  JSON_FORMAT_STRING       "Content-Type: application/json;charset=UTF-8"

//临时数组大小
#define  TEMP_FORMAT_MAX_SIZE     (128)

/*
    * 设置消息头
    * 参数1:数据格式,0默认,1为xml,2为json
    * 返回值int, 0表示成功, 其它表示失败
*/
static int curl_set_headers(CURL* curl, const int format,  struct curl_slist** headers)
{
    if(NULL == curl || NULL == headers)
    {
        EPRINT("curl_set_headers curl or headers ptr is null \n");
        return -1;       //CURL_PARAMS指针为NULL
    }

    char temp[TEMP_FORMAT_MAX_SIZE] = {0};
    if(FORMAT_XML == format)
    {
        strncpy(temp, (char*)XML_FORMAT_STRING, sizeof(temp)-1);
    }
    else if(FORMAT_JSON == format)
    {
        strncpy(temp, (char*)JSON_FORMAT_STRING, sizeof(temp)-1);
    }
    
    if(NULL != temp && '\0' != temp[0])
    {
        *headers = curl_slist_append(NULL, (char*)temp);
        if(NULL == headers)
        {
            EPRINT("curl_set_headers format error(%d) \n", errno);
            return -1;
        }
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *headers);
        return 0;
    }
    
    return -1;
}


/*
    * 设置传输的用户和密码验证
    * 参数1:curl指针,通过此指针进行设置用户密码操作
    * 参数2:curl参数结构体
    * 返回值int, 0表示成功,其他表示失败
*/
static int set_user_pwd(CURL* curl, const st_curl_params* curl_params)
{
    if(NULL == curl || NULL == curl_params)
    {
        EPRINT("set_user_pwd curl or curl_params ptr is null \n");
        return -1;       //CURL指针为NULL
    }

    if(curl_params->user[0] && curl_params->pwd[0])
    {
        char temp[MAX_TEMP_LEN] = {0};
        snprintf(temp, sizeof(temp)-1, "%s:%s", curl_params->user, curl_params->pwd);
        curl_easy_setopt(curl, CURLOPT_USERPWD, temp);
    }
    return 0;
}


/*
    * CURL公共操作
    * 参数1:curl指针,通过此指针进行相关设置
    * 参数2:curl数据传送格式,0默认,1为xml,2为json
    * 参数3:curl参数结构体
    * 返回值int,0表示成功,其他表示失败
*/
static int message_public_method(CURL* curl, st_curl_params* curl_params)
{


    if(NULL == curl || NULL == curl_params)
    {
        EPRINT("message_public_method curl or curl_params ptr is null \n");
        return -1;       //CURL指针为NULL
    }

    //指定url
    if(!(curl_params->ip[0]))
    {
        EPRINT("message_public_method ip ptr is null \n");
        return -1;
    }
    char url[MAX_URL_LEN] = {0};
    snprintf(url, sizeof(url)-1, "http://%s%s", curl_params->ip, curl_params->url_path);
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_PORT, curl_params->port);

    //设置用户名和密码
    int nCode = -1;
    nCode = set_user_pwd(curl, curl_params);
    if(0 != nCode)
    {
        EPRINT("message_public_method call set_user_pwd error(%d) \n", errno);
        return -1;
    }

    //禁用掉alarm这种超时
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    //设置超时时间
    if(0 >= curl_params->connect_timeout)
    {
        curl_params->connect_timeout = C_CONNECT_DEFAULT_TIMEOUT;
    }
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, curl_params->connect_timeout);

    if(0 >= curl_params->timeout)
    {
        curl_params->timeout = C_DEFAULT_TIMEOUT;
    }
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, curl_params->timeout);

    /*
    默认情况下libcurl完成一个任务以后,出于重用连接的考虑不会马上关闭,如果每次目标主机不一样,这里禁止重连接
    每次执行完curl_easy_perform,licurl会继续保持与服务器的连接。接下来的请求可以使用这个连接而不必创建新的连接,如果目标主机是同一个的话。
    */
    curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);

    return 0;

}


/*
	* curl返回值处理
	* 参数1: curl返回码
	* 返回值int, 0表示成功, 其他表示失败
*/
static int dealResCode(CURL* curl, const CURLcode res)
{
	//输出返回码代表的意思
	int nCode = 0;
    const char* pRes = NULL;
    pRes = curl_easy_strerror(res);
    DPRINT("%s\n",pRes);

    //http返回码
    long lResCode = 0;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &lResCode);

    if(CURLE_OK != res || 200 != lResCode)
    {
        //curl传送失败
        if(CURLE_OPERATION_TIMEOUTED == res)
        {
            nCode = 1;   //超时返回1
        }
        else
        {
            nCode = -1;    //其它错误返回-1
        }
        EPRINT("curl send msg error: pRes=%s, lResCode=%ld \n", pRes, lResCode);
    }
	
	return nCode;
}



/*
    * 通过put的方式操作
    * 参数1: curl指针
    * 参数1:curl参数结构体
    * 参数2:要发送的数据
    * 参数3:返回的数据结构体
    * 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
static int put_msg(CURL* curl,
                   st_curl_params* curl_params,
                   const char* msg,
                   st_curl_rec* curl_rec)
{
    CURLcode res = CURLE_OK;
    int nCode = -1;

    if(NULL == curl || NULL == curl_params || NULL == curl_rec)
    {
        EPRINT("put_msg curl or curl_params or curl_rec is null \n");
        return -1;       //CURL_PARAMS指针为NULL
    }

    //发送数据,以及发送方式
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
    if(NULL != msg && '\0' != msg[0])
    {
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg);
    }
    else
    {
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
    }


    //设置消息头
    struct curl_slist *headers = NULL;
    if(FORMAT_XML == curl_params->format || FORMAT_JSON == curl_params->format)
    {
        curl_set_headers(curl, curl_params->format, &headers);
    }

    //CURL公共操作方式
    nCode = message_public_method(curl, curl_params);
    if(0 != nCode)
    {
        //释放头结构体
        if(NULL != headers)
        {
            curl_slist_free_all(headers);
            headers = NULL;
        }

        EPRINT("put_msg call message_public_method failure \n");
        return -1;
    }

    // 设置回调函数
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_data_writer);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)curl_rec);
    res = curl_easy_perform(curl);

    //释放头结构体
    if(NULL != headers)
    {
        curl_slist_free_all(headers);
        headers = NULL;
    }
    
    //处理curl返回值
    nCode = dealResCode(curl, res);
	if(0 > nCode)
	{
		EPRINT("deal response code error \n");
	}

    //返回标识码
    return nCode;

}


/*
    * 通过delete的方式操作
    * 参数1: curl指针
    * 参数2: curl参数结构体
    * 参数3: 要发送的数据,此方式可空
    * 参数4: 返回的数据结构体
    * 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
static int delete_msg(CURL* curl,
                      st_curl_params* curl_params,
                      const char* msg,
                      st_curl_rec* curl_rec)
{
    CURLcode res = CURLE_OK;
    int nCode = 0;

    if(NULL == curl || NULL == curl_params || NULL == curl_rec)
    {
        EPRINT("delete_msg curl or curl_params or curl_rec ptr is null \n");
        return -1;         //CURL_PARAMS指针为NULL
    }

    //发送数据,以及发送方式
    curl_easy_setopt(curl,CURLOPT_CUSTOMREQUEST,"DELETE");

    //设置消息头
    struct curl_slist *headers = NULL;
    if(FORMAT_XML == curl_params->format || FORMAT_JSON == curl_params->format)
    {
         curl_set_headers(curl, curl_params->format, &headers);
    }

    //CURL公共操作方式
    nCode = message_public_method(curl, curl_params);
    if(0 != nCode)
    {
        //释放头结构体
        if(NULL != headers)
        {
            curl_slist_free_all(headers);
            headers = NULL;
        }

        EPRINT("delete_msg call message_public_method failure \n");
        return -1;
    }

    // 设置回调函数
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_data_writer);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)curl_rec);
    res = curl_easy_perform(curl);
    
    //释放头结构体
    if(NULL != headers)
    {
        curl_slist_free_all(headers);
        headers = NULL;
    }
    
    //处理curl返回值
    nCode = dealResCode(curl, res);
	if(0 > nCode)
	{
		EPRINT("deal response code error \n");
	}

    //返回标识码
    return nCode;

}


/*
    * 通过post的方式操作
    * 参数1: curl指针
    * 参数2: curl参数结构体
    * 参数3: 要发送的数据
    * 参数4: 返回的数据
    * 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
static int post_msg(CURL* curl,
                    st_curl_params* curl_params,
                    const char* msg,
                    st_curl_rec* curl_rec)
{
    CURLcode res = CURLE_OK;
    int nCode = 0;

    if(NULL == curl || NULL == curl_params || NULL == curl_rec)
    {
        EPRINT("post_msg curl or curl_params or curl_rec ptr is null \n");
        return -1;       //CURL_PARAMS指针为NULL
    }

    //发送数据,以及发送方式
    curl_easy_setopt(curl, CURLOPT_POST, 1);
    if(NULL != msg && '\0' != msg[0])
    {
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg);
    }
    else
    {
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
    }

    //设置消息头
    struct curl_slist *headers = NULL;
    if(FORMAT_XML == curl_params->format || FORMAT_JSON == curl_params->format)
    {
        curl_set_headers(curl, curl_params->format,  &headers);
    }

    //CURL公共操作方式
    nCode = message_public_method(curl, curl_params);
    if(0 != nCode)
    {
        //释放头结构体
        if(NULL != headers)
        {
            curl_slist_free_all(headers);
            headers = NULL;
        }

        EPRINT("post_msg call message_public_method failure \n");
        return -1;
    }

    // 设置回调函数
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_data_writer);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)curl_rec);
    res = curl_easy_perform(curl);

    //释放头结构体
    if(NULL != headers)
    {
        curl_slist_free_all(headers);
        headers = NULL;
        
    }
    
     //处理curl返回值
    nCode = dealResCode(curl, res);
	if(0 > nCode)
	{
		EPRINT("deal response code error \n");
	}

    //返回标识码
    return nCode;

}


/*
    * 通过get的方式操作
    * 参数1: curl结构体
    * 参数2: curl参数结构体
    * 参数3: 要发送的数据, 此方式可为空
    * 参数4: 返回的数据结构体
    * 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
static int get_msg(CURL* curl,
                   st_curl_params* curl_params,
                   const char* msg,
                   st_curl_rec* curl_rec)
{
    CURLcode res = CURLE_OK;
    int nCode = 0;

    if(NULL == curl || NULL == curl_params || NULL == curl_rec)
    {
        EPRINT("get_msg curl or curl_params or msg ptr is null \n");
        return -1;       //CURL_PARAMS指针为NULL
    }

    //设定传输方式
    curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);

    //设置消息头
    struct curl_slist *headers = NULL;
    if(FORMAT_XML == curl_params->format || FORMAT_JSON == curl_params->format)
    {
        curl_set_headers(curl, curl_params->format, &headers);
    }

    //CURL公共操作方式
    nCode = message_public_method(curl, curl_params);
    if(0 != nCode)
    {
        //释放头结构体
        if(NULL != headers)
        {
            curl_slist_free_all(headers);
        }

        EPRINT("get_msg call message_public_method failure \n");
        return -1;
    }

    // 设置回调函数
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_data_writer);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)curl_rec);
    res = curl_easy_perform(curl);

    //释放头结构体
    if(NULL != headers)
    {
        curl_slist_free_all(headers);
        headers = NULL;
    }
    
    //处理curl返回值
    nCode = dealResCode(curl, res);
	if(0 > nCode)
	{
		EPRINT("deal response code error \n");
	}

    //返回成功
    return nCode;

}


/*
    * 进行所有CURL开始之前的,全局变量初始化,放在主线程中
    * 返回值为int, 0表示成功,其他表示失败
*/
int curl_global_init_resource()
{

    if(0 == s_global_init_status)
    {

        if(CURLE_OK == curl_global_init(CURL_GLOBAL_ALL))
        {
            //返回成功
            s_global_init_status = 1;
            return 0;
        }
        else
        {
            EPRINT("curl_global_init error(%d)\n", errno);
            return -1;                  //CURL全局资源初始化失败
        }

    }

    return 0;
}


/*
    * 进行所有CURL开始结束的,全局变量初始化,放在主线程中
    * 返回值为int, 0表示成功,其他表示失败
*/
int curl_global_cleanup_resource()
{

    if(1 == s_global_init_status)
    {
        curl_global_cleanup();
        s_global_init_status = 0;
    }

    return 0;
}

/*
    * curl参数初始化
    * 1:ip地址
    * 2:url路径
    * 3:端口
    * 4:用户名
    * 5:验证密码
    * 6:数据格式(0默认,1为xml,2为json)
*/
int curl_init_params(st_curl_params* curl_params,
                     const char* ip,
                     const char* url_path,
                     const int port,
                     const char* user,
                     const char* pwd,
                     const int format)
{
    if(NULL == curl_params || NULL == ip)
    {
        EPRINT("curl_init_params curl_params or ip ptr is null \n");
        return -1;
    }
    memset(curl_params, 0, sizeof(*curl_params));            //初始化整个结构体
    strncpy(curl_params->ip, ip, sizeof(curl_params->ip)-1);
    curl_params->port = port;
    curl_params->format = format;

    if(NULL != url_path)
    {
        strncpy(curl_params->url_path, url_path, sizeof(curl_params->url_path)-1);
    }

    if((NULL != user) && (NULL != pwd))
    {
        strncpy(curl_params->user, user, sizeof(curl_params->user)-1);
        strncpy(curl_params->pwd, pwd, sizeof(curl_params->pwd)-1);
    }

    return 0;

}


/*
    * 数据发送方式
    * 参数1: curl指针
    * 参数2:curl参数结构体
    * 参数3:要发送的数据
    * 参数4:发送的方法:0使用GET, 1使用POST, 2使用PUT, 3使用DELETE,
    * 参数5:返回的数据信息,无需初始化,内部初始化
    * 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int send_msg(CURL* curl,
             st_curl_params* curl_params,
             const char* msg,
             const int method,
             st_curl_rec* curl_rec)
{
    if(NULL == curl || NULL == curl_params || NULL == curl_rec)
    {
        EPRINT("send_msg curl or curl_params or curl_rec ptr is null \n");
        return -1;
    }

    int nCode = -1;
    memset(curl_rec, 0, sizeof(st_curl_rec));
    switch(method)
    {
        case METHOD_GET:        //使用GET方法传送数据
        {
            nCode = get_msg(curl, curl_params, msg, curl_rec);
            return nCode;
        }
        case METHOD_POST:       //使用POST方法传送数据
        {
            nCode = post_msg(curl, curl_params, msg, curl_rec);
            return nCode;
        }
        case METHOD_PUT:        //使用PUT方法传送数据
        {
            nCode = put_msg(curl, curl_params, msg, curl_rec);
            return nCode;
        }
        case METHOD_DELETE:    //使用DELETE方法传送数据
        {
            nCode = delete_msg(curl, curl_params, msg, curl_rec);
            return nCode;
        }
        default:
        {
            EPRINT("send_msg method error\n");
            return -1;
        }
    }

    return -1;
}


/*
    * 设置发送路径
    * 参数1:cuel参数结构体
    * 参数2:url路径
*/
void set_url_path(st_curl_params* curl_params, char* url_path)
{
    strncpy(curl_params->url_path, url_path, sizeof(curl_params->url_path)-1);
}

/*
    * 设置连接超时时间
    * 参数1:cuel参数结构体
    * 参数2:时间秒数
*/
void set_connect_timeout(st_curl_params* curl_params, int connect_timeout)
{
    curl_params->connect_timeout =  connect_timeout;
}


/*
    * 设置传输超时时间
    * 参数1:cuel参数结构体
    * 参数2:时间秒数
*/
void set_timeout(st_curl_params* curl_params, int timeout)
{
    curl_params->timeout =  timeout;
}


/*
    * 下载文件
    * 参数1: curl指针
    * 参数2:参数结构体
    * 参数3:文件存放名
    * 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int download_file(CURL* curl, st_curl_params* curl_params, const char* filename)
{
    CURLcode res = CURLE_OK;
    FILE* pFile = NULL;
    int nCode = 0;

    if(NULL == curl || NULL == curl_params || NULL == filename || '\0' == filename[0])
    {
        EPRINT("download_file curl or curl_params or filename ptr is null \n");
        return -1;       //CURL_PARAMS指针为NULL
    }

    pFile = fopen(filename, "w");         //打开文件,返回结果用文件存储
    if (NULL == pFile)
    {
        EPRINT("download_file open file error(%d), %s\n", errno, filename);
        return -1;      //打开文件失败
    }

    //设定传输方式
    curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);

    //设置消息头
    struct curl_slist *headers = NULL;
    if(FORMAT_XML == curl_params->format || FORMAT_JSON == curl_params->format)
    {
        curl_set_headers(curl, curl_params->format, &headers);
    }

    //CURL公共操作方式
    nCode = message_public_method(curl, curl_params);
    if(0 != nCode)
    {
        //释放头结构体
        if(NULL != headers)
        {
            curl_slist_free_all(headers);
            headers = NULL;
        }

        if(NULL != pFile)
        {
            fclose(pFile);
            pFile = NULL;
        }

        EPRINT("download_file call message_public_method failure \n");
        return -1;
    }

    // 设置回调函数
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_write_file);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, pFile);
    res = curl_easy_perform(curl);

    //释放资源
    {
        //释放头结构体
        if(NULL != headers)
        {
            curl_slist_free_all(headers);
            headers = NULL;
        }
        
        if(NULL != pFile)
        {
            fclose(pFile);
            pFile = NULL;
        }
    }
   
    //处理curl返回值
    nCode = dealResCode(curl, res);
	if(0 > nCode)
	{
		EPRINT("deal response code error \n");
	}
    
    //返回成功
    return nCode;

}

/*
    * 从文件中读取内容post出去
    * 参数1: curl指针
    * 参数2:cuel参数结构体
    * 参数3:文件名
    * 参数4:返回数据,无需初始化,内部初始化
    * 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int upload_file_content(CURL* curl,
                        st_curl_params* curl_params,
                        const char* filename,
                        st_curl_rec* curl_rec)
{
    CURLcode res = CURLE_OK;
    FILE* pFile = NULL;
    struct stat file_info;
    curl_off_t fsize;
    int nCode = 0;

    if(NULL == curl || NULL == curl_params || NULL == filename || NULL == curl_rec)
    {
        EPRINT("upload_file_content curl or curl_params or filename or curl_rec ptr is null \n");
        return -1;            //CURL_PARAMS指针为NULL
    }

    if(stat(filename, &file_info))      //文件大小
    {
        EPRINT("upload_file_content get file info error(%d), %s\n", errno, filename);
        return -1;
    }
    fsize = (curl_off_t)file_info.st_size;

    pFile = fopen(filename, "rb");      //打开文件,返回结果用文件存储
    if (NULL == pFile)
    {
        EPRINT("upload_file_content open file error(%d), %s\n", errno, filename);
        return -1;                      //打开文件失败
    }

    //设定传输方式
    curl_easy_setopt(curl, CURLOPT_POST, 1);

    //设置消息头
    struct curl_slist *headers = NULL;
    if(FORMAT_XML == curl_params->format || FORMAT_JSON == curl_params->format)
    {
        curl_set_headers(curl, curl_params->format, &headers);
    }

    //CURL公共操作方式
    nCode = message_public_method(curl, curl_params);
    if(0 != nCode)
    {
        //释放头结构体
        if(NULL != headers)
        {
            curl_slist_free_all(headers);
            headers = NULL;
        }

        if(NULL != pFile)
        {
            fclose(pFile);
            pFile = NULL;
        }

        EPRINT("upload_file_content call message_public_method failure \n");
        return -1;
    }

    // 设置回调函数
    memset(curl_rec, 0, sizeof(st_curl_rec));
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, http_read_file);
    curl_easy_setopt(curl, CURLOPT_READDATA, pFile);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)fsize);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_data_writer);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)curl_rec);

    res = curl_easy_perform(curl);

    //释放资源
    {
        //释放头结构体
        if(NULL != headers)
        {
            curl_slist_free_all(headers);
            headers =NULL;
        }

        if(NULL != pFile)
        {
            fclose(pFile);
            pFile = NULL;
        }
    }

    //处理curl返回值
    nCode = dealResCode(curl, res);
	if(0 > nCode)
	{
		EPRINT("deal response code error \n");
	}

    //返回成功
    return nCode;

}



/*
    * 宏定义上传文件相关信息
*/
#define FILE_NAME_MAX_SIZE      (128)

/*
    * 从文件全路径中获取文件名指针
    * 返回文件名地址
*/
static const char* get_file_name_ptr(const char *path)
{
    if(!path)
    {
        return NULL;
    }

    //找最后一个斜杠/
    char *pname = strrchr(path, '/');
    if(!pname)
    {
        //没找到斜杠,则认为path就是文件名
        return path;
    }

    //找到最后一个斜杠, 反回指针加1
    return (char*)(pname + 1);
}


/*
    * 上传文件
    * 参数1: curl指针
    * 参数2: cuel参数结构体
    * 参数3: 文件名
    * 参数4: 返回数据,无需初始化,内部初始化
    * 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int upload_file(CURL* curl,
                st_curl_params* curl_params,
                const char* file_fullname,
                st_curl_rec* curl_rec)
{
    CURLcode res = CURLE_OK;
    int nCode = 0;
    struct curl_httppost *formpost = NULL;
    struct curl_httppost *lastptr = NULL;
    struct curl_slist *headerlist = NULL;
    static const char buf[] = "Expect:";

    //参数合法性检查
    if(NULL == curl || NULL == curl_params || NULL == file_fullname || '\0' == file_fullname[0] || NULL == curl_rec)
    {
        EPRINT("upload_file_content curl or curl_params or file_fullname or curl_rec ptr is null \n");
        return -1;            //CURL_PARAMS指针为NULL
    }

    //获取文件名
    const char* file_name = get_file_name_ptr(file_fullname);
    if(NULL == file_name || '\0' == file_name[0])
    {
        EPRINT("uploadFile call get_file_name failure, file_fullname=%s \n", file_fullname);
        return -1;
    }
    EPRINT("file_name=%s \n", file_name);

    //CURL公共操作方式
    nCode = message_public_method(curl, curl_params);
    if(0 != nCode)
    {
        EPRINT("upload_file_content call message_public_method failure \n");
        return -1;
    }

    /*
    Fill in the file upload field. This makes libcurl load data from
     the given file name when curl_easy_perform() is called.
    */
    curl_formadd(&formpost,
             &lastptr,
             CURLFORM_COPYNAME, "sendfile",
             CURLFORM_FILE, file_fullname,
             CURLFORM_END);

    /* Fill in the filename field */
    curl_formadd(&formpost,
               &lastptr,
               CURLFORM_COPYNAME, "filename",
               CURLFORM_COPYCONTENTS, file_name,
               CURLFORM_END);

    /* Fill in the submit field too, even if this is rarely needed */
    curl_formadd(&formpost,
              &lastptr,
              CURLFORM_COPYNAME, "submit",
              CURLFORM_COPYCONTENTS, "send",
              CURLFORM_END);

    headerlist = curl_slist_append(headerlist, buf);

    /* only disable 100-continue header if explicitly requested */
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
    curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);

    //返回值
    memset(curl_rec, 0, sizeof(st_curl_rec));
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_data_writer);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)curl_rec);


    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);

    /* then cleanup the formpost chain */

    if(NULL != formpost)
    {
        curl_formfree(formpost);
        formpost = NULL;
    }

    /* free slist */
    if(NULL != headerlist)
    {
        curl_slist_free_all(headerlist);
        headerlist = NULL;
    }

    //处理curl返回值
    nCode = dealResCode(curl, res);
	if(0 > nCode)
	{
		EPRINT("deal response code error \n");
	}
    
    return nCode;
}



/*
* main.c
*/
#include <stdio.h>
#include <string.h>
#include "cluster_curl.h"

#define DPRINT printf
#define EPRINT printf

/*
	* 通过GET发送数据示例,delete类似
*/
void test_get_method()
{
	int nCode = -1;
	
	//初始化st_curl_params相关参数
    char* ip = "10.200.0.225";
	char* url_path = "/index.html?user=user&name=name";
	int   port = 80;
	char* user = "USER";
	char* pwd = "PWD";
    int   format = FORMAT_XML;
	st_curl_params curl_params;
    curl_init_params(&curl_params, ip, url_path, port, user, pwd, format);
	
	
	//设置返回数据结构体
    st_curl_rec curl_rec; 
	
	
	//使用GET方式发送数据method = 0,数据格式为默认format = 0,msg发送数据为空,curl_rec为返回数据
	char* msg = NULL;
	int method = METHOD_GET;
    CURL* curl = NULL; 
    curl = curl_init_resource();
	nCode = send_msg(curl, &curl_params, msg, method, &curl_rec);
	DPRINT("get:\n%s\nsize:%d\n", curl_rec.rec, curl_rec.len);
    curl_release_resource(curl);
	
}

/*
	* 通过POST发送数据示例,put类似
*/
void test_post_method()
{
	int nCode = -1;
	
	//初始化st_curl_params关参数 ,数据格式为json即format = 2
    char* ip = "10.200.0.225";
	char* url_path = NULL;
	int   port = 80;
	char* user = "USER";
	char* pwd = "PWD";
    int   format = FORMAT_JSON;
	st_curl_params curl_params;
    curl_init_params(&curl_params, ip, url_path, port, user, pwd, format);
  
	//设置返回数据结构体
    st_curl_rec curl_rec; 
	
	//使用POST方式发送数据method = 1,msg发送数据,curl_rec为返回数据
	int method = METHOD_PUT;
	//存放要发送的数据,下列为json数据
	char* msg = "{\"UserName\":\"user\",\"UserPwd\":\"pwd\"}";
    CURL* curl = NULL; 
    curl = curl_init_resource();
	nCode = send_msg(curl, &curl_params, msg, method, &curl_rec);
	DPRINT("post:\n%s\nsize:%d\n", curl_rec.rec, curl_rec.len);
    curl_release_resource(curl);

	
}

/*
	* 上传文件
*/
void test_upload_file()
{
	int nCode = -1;
	//初始化st_curl_params相关参数 
    char* ip = "10.200.0.225";
	char* url_path = NULL;
	int   port = 80;
	char* user = "USER";
	char* pwd = "PWD";
    int   format = FORMAT_DEFAULT;
	st_curl_params curl_params;
    curl_init_params(&curl_params, ip, url_path, port, user, pwd, format);
	
	//设置上传文件
	char* filename = "./b.zip";
	
    //设置返回数据结构体
    st_curl_rec curl_rec; 
	
	//调用上传函数,返回0为成功,其他为失败
    CURL* curl = NULL; 
    curl = curl_init_resource();
	nCode = upload_file(curl, &curl_params, filename, &curl_rec);
	DPRINT("upload:\n%s\nsize:%d\n", curl_rec.rec, curl_rec.len);
    curl_release_resource(curl);
	
}

/*
	* 下载文件
*/
void test_download_file()
{
	int nCode = -1;
	
	//初始化st_curl_params相关参数 
    char* ip = "10.200.0.225";
	char* url_path = NULL;
	int   port = 80;
	char* user = "USER";
	char* pwd = "PWD";
    int   format = FORMAT_XML;
	st_curl_params curl_params;
    curl_init_params(&curl_params, ip, url_path, port, user, pwd, format);
	
	//设置下载文件存放
	char* filename = "./test.html";
	
	//调用下载函数,成功返回0,其他为失败
    CURL* curl = NULL; 
    curl = curl_init_resource();
	nCode = download_file(curl, &curl_params, filename);
    curl_release_resource(curl);
	
}


/*
	* 传送数据方式,分为下列几步
	* 1.全局初始化,放在主线程中
	* 2.初始化st_curl_params相关参数
	    char ip[128]     curl请求的ip
		int   port       curl请求ip的端口
	    char user[64]    需要对方验证时使用,请求对方需要的用户名,可为空
	    char pwd[64]     需要对方验证时使用,请求对方需要的密码,可为空
	* 3.调用发送数据函数send_msg、上传文件函数upload_file、下载文件函数download_file
	* 4.释放全局资源,放在主线程中
*/
int main()
{
    int nCode = -1;

    
     //全局资源初始化,放在主线程
     nCode = curl_global_init_resource();  
  
  
    
    //具体操作传送数据操作
    test_get_method();
    //test_post_method();
    
    //具体上传,下载数据操作
   // test_download_file();
    //test_upload_file();
    

    
    
     //全局资源清除,放在主线程中
    nCode = curl_global_cleanup_resource();
  


    return 0;
	
}




/*
* Makefile
*/

## c/c++ 代码编译Makefile
########################常规配置势##################################################
##目标文件
TARGET = main

##安装目录
INSTALL_DIR = /tmp

##包含头文件路弿
# -I/xx/xx/include
INC_DIR = -I/usr/include/

##依赖帿
# -L/xx/xx/lib -lstd
LIB_DEPENDS = -L/usr/lib64/ -lcurl

##编译选项
CFLAGS = -Wall -O -g
# -Wall  输出所有告諿
# -O     在编译时进行优化
# -g     编译debug版本

######################################################################################
##编译器选用
CC = gcc
XX = g++

##产生一个所暿c .cpp文件列表
C_SRC = $(wildcard *.c)
CXX_SRC = $(wildcard *.cpp)

##产生一个所暿c 文件 对应瘿o文件列表
#C_OBJS = $(C_SRC:%.c=%.o)
C_OBJS = $(subst .c,.o,$(C_SRC))
#CXX_OBJS = $(CXX_SRC:%.cpp=%.o)
CXX_OBJS = $(subst .cpp,.o,$(CXX_SRC))
ALL_OBJ = $(C_OBJS) $(CXX_OBJS)

##把所暿c文件生成.o文件
%.o:%.c
	$(CC) $(CFLAGS) -c $< -o $@ $(INC_DIR)

##把所暿cpp文件生成.o文件
%.o:%.cpp
	$(XX) $(CFLAGS) -c $< -o $@ $(INC_DIR)

##目标文件,依赖OBJS中的.o文件
all: $(TARGET)
$(TARGET): $(ALL_OBJ)
	$(CC) $^ -o $(TARGET) $(INC_DIR) $(LIB_DEPENDS)
	chmod a+x $(TARGET)

##安装命令	
install: all
	mkdir -p $(INSTALL_DIR)
	cp -R $(TARGET) $(INSTALL_DIR)
	
##执行make clean操作
clean:
	rm -rf *.o  $(TARGET)

.PHONY: all clean distclean install





  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值