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