curl的简单封装(c++版本)
curl的基本实现功能
(1). get , post , put, delete 发送数据
(2). 上传文件
(3). 下载文件
辅助代码,线程锁的实现
(1). curl_global_init 不是线程安全的通过锁机制
(2). curl_global_cleanup
不是线程安全的通过锁机制
/*
* manager_lock.h
*/
/*
* 实现mutex的封装,有以下操作:
* 1.mutex初始化
* 2.mutex加锁
* 3.mutex解锁
* 4.mutex释放
*/
#ifndef MUTEX_LOCK_H_
#define MUTEX_LOCK_H_
#include <pthread.h>
//for test
#define EPRINT printf
#define DPRINT printf
/* MUTEX */
/*0表示成功,-1表示失败 */
class MutexLock
{
public:
MutexLock();
~MutexLock();
//mutex加锁
int lock();
//mutex解锁
int unlock();
private:
//mutex初始化
void mutexInit();
//mutex释放
void mutexDestroy();
private:
//mutex
pthread_mutex_t m_Mutex;
};
#endif //MUTEX_LOCK_H_
/*
* manager_lock.cpp
*/
/*
* 实现mutex的封装的具体实现,有以下操作:
* 1.mutex初始化
* 2.mutex加锁
* 3.mutex解锁
* 4.mutex释放
*/
#include "manager_lock.h"
#include <stdio.h>
#include <errno.h>
MutexLock::MutexLock()
{
mutexInit();
}
MutexLock::~MutexLock()
{
mutexDestroy();
}
/*
* 对mutex进行初始化
*/
void MutexLock::mutexInit()
{
pthread_mutex_init(&m_Mutex, NULL);
}
/*
* 对mutex进行加锁操作
* 返回值为整数,0表示成功,其他表示失败
*/
int MutexLock::lock()
{
int nCode = -1;
nCode = pthread_mutex_lock(&m_Mutex);
if(0 == nCode)
{
return 0;
}
else
{
EPRINT("mutex lock error(%d)\n", errno);
return -1; //加锁失败
}
}
/*
* 对mutex进行解锁操作
* 返回值为整数,0表示成功,其他表示失败
*/
int MutexLock::unlock()
{
int nCode = -1;
nCode = pthread_mutex_unlock(&m_Mutex);
if(0 == nCode)
{
return 0;
}
else
{
EPRINT("mutex unlock error(%d)\n", errno);
return -1; //解锁失败
}
}
/*
* 对mutex进行释放
*/
void MutexLock::mutexDestroy()
{
pthread_mutex_destroy(&m_Mutex);
}
curl代码实现
(1). curl_global_init和curl_global_cleanup 不是线程安全的通过锁机制, 且只能使用一次, 通过一个静态成员变量加以限制
(2). get, post, put, delete, 上传文件, 下载文件的一些公用操作进行封装
(3). curl的封装,这里针对http, 作为一个工具类, 通过建立临时类即可以保证线程的安全性
/*
* manager_curl.h
*/
/*
* curl的封装,有以下操作:
* 1.设置服务器参数
* 2.发送信息:get、post、put、delete
* 3.上传文件处理
* 4.下载文件
*/
#ifndef MANAGER_CURL_H_
#define MANAGER_CURL_H_
#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <string>
#include "manager_lock.h"
//for test
#define EPRINT printf
#define DPRINT printf
/*
* 宏定义发送方法
*/
#define METHOD_GET 0 //get方法
#define METHOD_POST 1 //post方法
#define METHOD_PUT 2 //put方法
#define METHOD_DELETE 3 //delete方法
/*
* 宏定义数据格式
*/
#define FORMAT_DEFAULT 0 //默认数据格式
#define FORMAT_XML 1 //xml数据格式
#define FORMAT_JSON 2 //json数据格式
/*
* 宏定义超时时间
*/
#define CONNECT_DEFAULT_TIMEOUT 10 //连接最长时间
#define DEFAULT_TIMEOUT 600 //传输最长时间
class ClusterCurl
{
private:
CURL* m_pCurl; //curl指针
struct curl_slist* m_pHeaders; //http消息头
std::string m_sIP; //curl请求的ip
unsigned int m_nPort; //curl请求ip的端口
std::string m_sUser; //需要对方验证时使用,请求对方需要的用户名
std::string m_sPwd; //需要对方验证时使用,请求对方需要的密码
std::string m_sUrlPath; //url路径
static bool s_bGlobalInitStatus; //判断是否已进行全局初始化,0表示未初始化,1表示已经初始化
static MutexLock s_MutexLock; //mutex锁对象
unsigned int m_contect_timeout; //连接最长时间
unsigned int m_timeout; //传输最长时间
public:
ClusterCurl();
ClusterCurl(const std::string& sIP,
const unsigned int nPort,
const std::string& sUser,
const std::string& sPwd);
~ClusterCurl();
// 设置等待连接最长时间
void setConnectTimeout(unsigned int nTime);
// 设置传输最长时间
void setTimeout(unsigned int nTime);
//设置服务器参数
void setServer(const std::string& sIP,
const unsigned int nPort,
const std::string& sUser,
const std::string& sPwd);
//设置URL路径
void setUrlPath(const std::string& sUrlPath);
//发送消息发送方式
int sendMsg(const std::string& sMsg,
const int nMethod,
const int nFormat,
std::string& sRec);
//下载文件
int downloadFile(const std::string& sFileName, const int nFormat);
//从文件中读取内容post出去
int uploadFileContent(const std::string& sFileName, const int nFormat, std::string& sRec);
//上传文件
int uploadFile(const std::string& sFileFullname, std::string& sRec);
//进行所有CURL开始之前,全局变量初始化,放在主线程中
static int globalInit();
//全局资源释放,行所有CURL结束之前,放在主线程中
static int globalCleanup();
//对单一curl资源进行初始化,不封装在构造函数的好处是,可以对curl初始化异常时进行处理
int initCurlResource();
//对单一curl资源进行释放,可用可不用, 不用则留给类析构释放, 使用好处时,使用者可以对异常进行处理
int releaseCurlResource();
private:
//设置请求用户名和密码
int setUserPwd();
//设置数据格式
int setDataFormat(const int nFormat);
//回调函数,将文件内容读取到缓存中
static size_t httpReadFile(void* buffer, size_t size, size_t nmemb, void* file);
//回调函数,将缓存内容写到文件中
static size_t httpWriteFile(void* buffer, size_t size, size_t nmemb, void* file);
//回调函数,将返回缓存数据写出
static size_t httpDataWriter(void* buffer, size_t size, size_t nmemb, void* content);
//通过get的方式发送信息
int getMsg(const std::string& sMsg, const int nFormat, std::string& sRec);
//通过post的方式发送信息
int postMsg(const std::string& sMsg, const int nFormat, std::string& sRec);
//通过put的方式发送信息
int putMsg(const std::string& sMsg, const int nFormat, std::string& sRec);
//通过delete进行操作
int deleteMsg(const std::string& sMsg, const int nFormat, std::string& sRec);
//curl一些公用操作
int messagePublicMethod(const int nFormat);
//curl返回值处理
int dealResCode(const CURLcode res);
//从文件全路径中获取文件名指针
const char* getFileName(const char *path);
};
#endif //MANAGER_CURL_H_
/*
* manager_curl.cpp
*/
/*
* curl的封装的具体实现,有以下操作:
* 1.设置服务器参数
* 2.发送信息:get、post、put、delete
* 3.上传文件处理
* 4.下载文件
*/
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include "manager_curl.h"
bool ClusterCurl::s_bGlobalInitStatus = 0;
MutexLock ClusterCurl::s_MutexLock;
/*
* 默认构造函数
*/
ClusterCurl::ClusterCurl():m_pCurl(NULL),
m_pHeaders(NULL),
m_sIP(),
m_nPort(),
m_sUser(),
m_sPwd(),
m_contect_timeout(0),
m_timeout(0)
{
}
/*
* 构造函数,进行成员变量初始化
* 参数1:请求的ip地址
* 参数2:请求ip地址的端口
* 参数3:对方验证用户名
* 参数4:对方验证密码
*/
ClusterCurl::ClusterCurl(const std::string& sIP,
const unsigned int nPort,
const std::string& sUser,
const std::string& sPwd)
:m_pCurl(NULL),
m_pHeaders(NULL),
m_sIP(sIP),
m_nPort(nPort),
m_sUser(sUser),
m_sPwd(sPwd),
m_contect_timeout(0),
m_timeout(0)
{
}
/*
* 析构函数,进行释放资源
*/
ClusterCurl::~ClusterCurl()
{
try
{
if(NULL != this->m_pHeaders)
{
curl_slist_free_all(this->m_pHeaders);
this->m_pHeaders = NULL;
}
if(NULL != this->m_pCurl)
{
releaseCurlResource();
}
}
catch(...) //吞下异常,防止异常逃离析构函数
{
EPRINT("~ClusterCurl api exception error(%d) \n", errno);
}
}
/*
* 进行所有CURL开始之前的,全局变量初始化,放在主线程中
* 返回值为int, 0表示成功,其他表示失败
*/
int ClusterCurl::globalInit()
{
int nCode = -1;
int nLockJudge = -1;
int nUnlockJudge = -1;
try
{
nLockJudge = ClusterCurl::s_MutexLock.lock();
nCode = nLockJudge;
if(0 != nCode)
{
EPRINT("globalInit mutex lock error(%d)\n", errno);
return nCode;
}
if(0 == s_bGlobalInitStatus)
{
if(CURLE_OK == curl_global_init(CURL_GLOBAL_ALL))
{
//返回成功
s_bGlobalInitStatus = 1;
}
else
{
EPRINT("globalInit error(%d)\n", errno);
nCode = -1; //CURL全局资源初始化失败
}
}
nUnlockJudge = ClusterCurl::s_MutexLock.unlock();
return nCode;
}
catch(...)
{
if(0 == nLockJudge && 0 != nUnlockJudge)
{
ClusterCurl::s_MutexLock.unlock();
}
EPRINT("global init api exception(%d)\n", errno);
return -1; //异常接口
}
}
/*
* 进行所有CURL开始结束的,全局变量初始化,放在主线程中
* 返回值为int, 0表示成功,其他表示失败
*/
int ClusterCurl::globalCleanup()
{
int nLockJudge = -1;
int nUnlockJudge = -1;
int nCode = -1;
try
{
nLockJudge = ClusterCurl::s_MutexLock.lock();
nCode = nLockJudge;
if(0 != nCode)
{
EPRINT("globalCleanup mutex lock error(%d)\n", errno);
return nCode;
}
if(1 == s_bGlobalInitStatus)
{
curl_global_cleanup();
s_bGlobalInitStatus = 0;
}
nUnlockJudge = ClusterCurl::s_MutexLock.unlock();
nCode = nUnlockJudge;
return nCode;
}
catch(...)
{
if(0 == nLockJudge && 0 != nUnlockJudge)
{
ClusterCurl::s_MutexLock.unlock();
}
EPRINT("globalCleanup api exception(%d)\n", errno);
return -1; //异常接口
}
}
/*
* 进行单个线程CURL简单资源进行初始化
* 返回值int, 0表示成功, 其它表示失败
*/
int ClusterCurl::initCurlResource()
{
this->m_pCurl = curl_easy_init();
if(NULL == this->m_pCurl)
{
EPRINT("curl easy init failure \n");
return -1;
}
else
{
return 0;
}
}
/*
* 进行单个线程CURL简单资源进行释放
* 返回值为int, 0表示成功,其他表示失败
*/
int ClusterCurl::releaseCurlResource()
{
//判断参数的合法性
if(NULL == this->m_pCurl)
{
EPRINT("releaseCurlResource curl ptr is null \n");
return -1; //CURL指针为NULL
}
//释放curl指针
curl_easy_cleanup(this->m_pCurl);
this->m_pCurl = NULL;
return 0;
}
/*
* 设置传输的用户和密码验证
* 参数1:curl指针,通过此指针进行设置用户密码操作
* 返回值int, 0表示成功,其他表示失败
*/
int ClusterCurl::setUserPwd()
{
if(NULL == this->m_pCurl)
{
EPRINT("setUserPwd curl ptr is null \n");
return -1; //CURL指针为NULL
}
std::string sUserPwd;
if((!(this->m_sUser.empty())) && (!(this->m_sPwd.empty())))
{
sUserPwd = this->m_sUser + ":" + this->m_sPwd;
curl_easy_setopt(this->m_pCurl, CURLOPT_USERPWD, (char*)sUserPwd.c_str());
}
return 0;
}
/*
* 设置等待连接最长时间
* 参数1:最长时间秒数
*/
void ClusterCurl::setConnectTimeout(unsigned int nTime)
{
this->m_contect_timeout = nTime;
}
/*
* 设置传输最长时间
* 参数1:最长时间秒数
*/
void ClusterCurl::setTimeout(unsigned int nTime)
{
this->m_timeout = nTime;
}
/*
* 宏定义数据格式字符串
*/
//XML格式
#define XML_FORMAT_STRING "Content-Type: application/xml;charset=UTF-8"
//JSON格式
#define JSON_FORMAT_STRING "Content-Type: application/json;charset=UTF-8"
/*
* 设置数据格式
* 参数1:CURL指针
* 参数2:发送数据格式,0默认,1为xml,2为json
* 返回值int,0表示成功,其它表示失败
*/
int ClusterCurl::setDataFormat(const int nFormat)
{
if(NULL == this->m_pCurl)
{
EPRINT("setDataFormat curl ptr is null \n");
return -1; //CURL指针为NULL
}
std::string sFormatStr;
if(FORMAT_XML == nFormat)
{
sFormatStr = XML_FORMAT_STRING;
}
else if(FORMAT_JSON == nFormat)
{
sFormatStr = JSON_FORMAT_STRING;
}
if(!sFormatStr.empty())
{
//非空设置相应格式,空则不设置
this->m_pHeaders = curl_slist_append(NULL, (char*)sFormatStr.c_str());
if(NULL == this->m_pHeaders)
{
EPRINT("setDataFormat set format error(%d) \n", errno);
return -1;
}
curl_easy_setopt(this->m_pCurl, CURLOPT_HTTPHEADER, this->m_pHeaders);
}
return 0;
}
/*
* 设置服务器参数
* 参数1:服务器ip
* 参数2:服务器ip相关端口
* 参数3:服务器用户名
* 参数4:服务器密码
*/
void ClusterCurl::setServer(const std::string& sIP,
const unsigned int nPort,
const std::string& sUser,
const std::string& sPwd)
{
this->m_sIP = sIP;
this->m_nPort = nPort;
this->m_sUser = sUser;
this->m_sPwd = sPwd;
}
/*
* 设置URL路径
* 参数1:URL路径
*/
void ClusterCurl::setUrlPath(const std::string& sUrlPath)
{
this->m_sUrlPath = sUrlPath;
}
/*
* 回调函数,处理返回的数据
* 参数1:缓存存放
* 参数2:缓存块数
* 参数3:缓存每块大小
* 参数4:WRITEDATA对应的数据流
* 返回值, 数据所占字节数
*/
size_t ClusterCurl::httpDataWriter(void* buffer, size_t size, size_t nmemb, void* content)
{
long totalSize = size*nmemb;
std::string* symbolBuffer = (std::string*)content;
if(symbolBuffer)
{
symbolBuffer->append((char *)buffer, ((char*)buffer)+totalSize);
return totalSize;
}
else
{
EPRINT("ClusterCurl httpDataWriter data error(%d) \n", errno);
return 0;
}
}
/*
* 回调函数,上传文件处理,读文件
* 参数1:缓存存放
* 参数2:缓存块数
* 参数3:缓存每块大小
* 参数4:READDATA对应的数据流
* 返回值,数据所占字节数
*/
size_t ClusterCurl::httpReadFile(void* buffer, size_t size, size_t nmemb, void* file)
{
return fread(buffer, size, nmemb, (FILE *)file);
}
/*
* 回调函数,下载文件处理,写文件
* 参数1:缓存存放
* 参数2:缓存块数
* 参数3:缓存每块大小
* 参数4:WRITEDATA对应的数据流
* 返回值,数据所占字节数
*/
size_t ClusterCurl::httpWriteFile(void* buffer, size_t size, size_t nmemb, void* file)
{
return fwrite(buffer, size, nmemb, (FILE *)file);
}
/*
* 数据发送方式
* 参数1:要发送的数据
* 参数2:发送的方法:0使用GET, 1使用POST, 2使用PUT, 3使用DELETE
* 参数3:数据头格式,0表示默认,1表示xml,2为json
* 参数4:返回的数据信息
* 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int ClusterCurl::sendMsg(const std::string& sMsg,
const int nMethod,
const int nFormat,
std::string& sRec)
{
int nCode = -1;
sRec = ""; //清空数据
switch(nMethod)
{
case METHOD_GET: //使用GET方法传送数据
{
nCode = getMsg(sMsg, nFormat, sRec);
return nCode;
}
case METHOD_POST: //使用POST方法传送数据
{
nCode = postMsg(sMsg, nFormat, sRec);
return nCode;
}
case METHOD_PUT: //使用PUT方法传送数据
{
nCode = putMsg(sMsg, nFormat, sRec);
return nCode;
}
case METHOD_DELETE: //使用DELETE方法传送数据
{
nCode = deleteMsg(sMsg, nFormat, sRec);
return nCode;
}
default:
{
EPRINT("sendMsg method error\n");
return -1;
}
}
}
/*
* CURL公共操作
* 参数1:curl指针,通过此指针进行相关设置
* 返回值int,0表示成功,其他表示失败
*/
int ClusterCurl::messagePublicMethod(const int nFormat)
{
int nCode = -1;
try
{
if(NULL == this->m_pCurl)
{
EPRINT("messagePublicMethod curl ptr is null\n");
return -1; //CURL指针为NULL
}
//参数合法性检测
if(0 > nFormat)
{
EPRINT("messagePublicMethod params error, nFormat=%d \n", nFormat);
return -1; //CURL指针为NULL
}
//指定url
if(this->m_sIP.empty())
{
EPRINT("messagePublicMethod ip is empty\n");
return -1;
}
std::string sUrl;
sUrl = sUrl + "http://" + this->m_sIP + this->m_sUrlPath;
DPRINT("sUrl: %s\n", sUrl.c_str());
curl_easy_setopt(this->m_pCurl, CURLOPT_URL, (char*)sUrl.c_str());
curl_easy_setopt(this->m_pCurl, CURLOPT_PORT, this->m_nPort);
//设置用户名和密码
nCode = setUserPwd();
if(0 != nCode)
{
EPRINT("messagePublicMethod setUserPwd error(%d) \n", errno);
return -1;
}
//设置数据格式
nCode = setDataFormat(nFormat);
if(0 != nCode)
{
EPRINT("messagePublicMethod setDataFormat error(%d) \n", errno);
return -1;
}
//禁用掉alarm这种超时
curl_easy_setopt(this->m_pCurl, CURLOPT_NOSIGNAL, 1);
//设置超时时间
if(0 >= this->m_contect_timeout)
{
this->m_contect_timeout = CONNECT_DEFAULT_TIMEOUT;
}
curl_easy_setopt(this->m_pCurl, CURLOPT_CONNECTTIMEOUT, this->m_contect_timeout);
if(0 >= this->m_timeout)
{
this->m_timeout = DEFAULT_TIMEOUT;
}
curl_easy_setopt(this->m_pCurl, CURLOPT_TIMEOUT, this->m_timeout);
/*
第一:默认情况下libcurl完成一个任务以后,出于重用连接的考虑不会马上关闭,如果每次目标主机不一样,这里禁止重连接
第二:每次执行完curl_easy_perform,licurl会继续保持与服务器的连接。接下来的请求可以使用这个连接而不必创建新的连接,如果目标主机是同一个的话。
这样可以减少网络开销。
*/
curl_easy_setopt(this->m_pCurl, CURLOPT_FORBID_REUSE, 1);
return 0;
}
catch(...)
{
EPRINT("messagePublicMethod api exception(%d)\n", errno);
return -1; //发送信息公共接口异常
}
}
/*
* curl返回值处理
* 参数1: curl返回码
* 返回值int, 0表示成功, 1表示超时, 其他表示失败
*/
int ClusterCurl::dealResCode(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(this->m_pCurl, 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:要发送的数据
* 参数2: 数据头格式,0为默认,1为xml,2为json
* 参数3:返回的数据
* 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int ClusterCurl::putMsg(const std::string& sMsg, const int nFormat, std::string& sRec)
{
CURLcode res = CURLE_OK;
int nCode = -1;
try
{
if(NULL == this->m_pCurl)
{
EPRINT("putMsg curl ptr is null\n");
return -1; //CURL指针为NULL
}
//发送数据,以及发送方式
curl_easy_setopt(this->m_pCurl, CURLOPT_CUSTOMREQUEST, "PUT");
if(sMsg.empty())
{
curl_easy_setopt(this->m_pCurl, CURLOPT_POSTFIELDS, "");
}
else
{
curl_easy_setopt(this->m_pCurl, CURLOPT_POSTFIELDS, (char*)sMsg.c_str());
}
//CURL公共操作方式
nCode = messagePublicMethod(nFormat);
if(0 != nCode)
{
EPRINT("putMsg call messagePublicMethod error(%d) \n", errno);
return -1;
}
// 设置回调函数
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEFUNCTION, httpDataWriter);
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEDATA, (void*)&sRec);
res = curl_easy_perform(this->m_pCurl);
//处理curl返回值
nCode = dealResCode(res);
if(0 > nCode)
{
EPRINT("deal response code error \n");
}
return nCode;
}
catch(...)
{
EPRINT("putMsg api exception(%d)\n", errno);
return -1; // 接口异常
}
}
/*
* 通过delete的方式操作
* 参数1:要发送的数据,此方式可空
* 参数2:数据头格式,0为默认,1为xml,2为json
* 参数3:数据头格式,0表示默认,1表示xml,2为json
* 参数4:返回的数据
* 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int ClusterCurl::deleteMsg(const std::string& sMsg, const int nFormat, std::string& sRec)
{
CURLcode res = CURLE_OK;
int nCode = -1;
try
{
if(NULL == this->m_pCurl)
{
EPRINT("deleteMsg curl ptr is null\n");
return -1; //CURL指针为NULL
}
//发送数据,以及发送方式
curl_easy_setopt(this->m_pCurl,CURLOPT_CUSTOMREQUEST,"DELETE");
//CURL公共操作方式
nCode = messagePublicMethod(nFormat);
if(0 != nCode)
{
EPRINT("deleteMsg call messagePublicMethod error(%d) \n", errno);
return -1;
}
// 设置回调函数
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEFUNCTION, httpDataWriter);
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEDATA, (void*)&sRec);
res = curl_easy_perform(this->m_pCurl);
//处理curl返回值
nCode = dealResCode(res);
if(0 > nCode)
{
EPRINT("deal response code error \n");
}
return nCode;
}
catch(...)
{
EPRINT("deleteMsg api exception(%d)\n", errno);
return -1; //接口异常
}
}
/*
* 通过post的方式操作
* 参数1:要发送的数据
* 参数2:数据头格式,0为默认,1为xml,2为json
* 参数3:数据头格式,0表示默认,1表示xml,2为json
* 参数4:返回的数据
* 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int ClusterCurl::postMsg(const std::string& sMsg, const int nFormat, std::string& sRec)
{
CURLcode res = CURLE_OK;
int nCode = -1;
try
{
if(NULL == this->m_pCurl)
{
EPRINT("postMsg curl ptr is null\n");
return -1; //CURL指针为NULL
}
//发送数据,以及发送方式
curl_easy_setopt(this->m_pCurl, CURLOPT_POST, 1);
if(sMsg.empty())
{
curl_easy_setopt(this->m_pCurl, CURLOPT_POSTFIELDS, "");
}
else
{
curl_easy_setopt(this->m_pCurl, CURLOPT_POSTFIELDS, (char*)sMsg.c_str());
}
//CURL公共操作方式
nCode = messagePublicMethod(nFormat);
if(0 != nCode)
{
EPRINT("postMsg call messagePublicMethod error(%d) \n", errno);
return -1;
}
// 设置回调函数
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEFUNCTION, httpDataWriter);
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEDATA, (void*)&sRec);
res = curl_easy_perform(this->m_pCurl);
//处理curl返回值
nCode = dealResCode(res);
if(0 > nCode)
{
EPRINT("deal response code error \n");
}
return nCode;
}
catch(...)
{
EPRINT("postMsg api exception(%d)\n", errno);
return -1; // 接口异常
}
}
/*
* 通过get的方式操作
* 参数1:要发送的数据, 此方式可为空
* 参数2:数据头格式,0表示默认,1表示xml,2为json
* 参数3:返回的数据
* 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int ClusterCurl::getMsg(const std::string& sMsg, const int nFormat, std::string& sRec)
{
CURLcode res = CURLE_OK;
int nCode = -1;
try
{
if(NULL == this->m_pCurl)
{
EPRINT("getMsg curl ptr is null\n");
return -1; //CURL指针为NULL
}
//设定传输方式
curl_easy_setopt(this->m_pCurl, CURLOPT_HTTPGET, 1);
//CURL公共操作方式
nCode = messagePublicMethod(nFormat);
if(0 != nCode)
{
EPRINT("getMsg call messagePublicMethod error(%d) \n", errno);
return -1;
}
// 设置回调函数
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEFUNCTION, httpDataWriter);
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEDATA, (void*)&sRec);
res = curl_easy_perform(this->m_pCurl);
//处理curl返回值
nCode = dealResCode(res);
if(0 > nCode)
{
EPRINT("deal response code error \n");
}
return nCode;
}
catch(...)
{
EPRINT("getMsg api exception(%d)\n", errno);
return -1; //接口异常
}
}
/*
* 下载文件
* 参数1:文件存放名
* 参数2:数据头格式,0表示默认,1表示xml,2为json
* 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int ClusterCurl::downloadFile(const std::string& sFileName, const int nFormat)
{
CURLcode res = CURLE_OK;
FILE* pFile = NULL;
int nCode = -1;
try
{
if(sFileName.empty())
{
EPRINT("downloadFile filename is empty\n");
return -1; //文件名为空
}
pFile = fopen((char*)sFileName.c_str(), "w"); //打开文件,返回结果用文件存储
if (NULL == pFile)
{
EPRINT("downloadFile open file error(%d), %s\n", errno, (char*)sFileName.c_str());
return -1; //打开文件失败
}
//设定传输方式
curl_easy_setopt(this->m_pCurl, CURLOPT_HTTPGET, 1);
//CURL公共操作方式
nCode = messagePublicMethod(nFormat);
if(0 != nCode)
{
if(NULL != pFile)
{
fclose(pFile);
pFile = NULL;
}
EPRINT("downloadFile call messagePublicMethod error(%d) \n", errno);
return -1;
}
// 设置回调函数
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEFUNCTION, httpWriteFile);
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEDATA, pFile);
res = curl_easy_perform(this->m_pCurl);
//处理curl返回值
nCode = dealResCode(res);
if(0 > nCode)
{
EPRINT("deal response code error \n");
}
//关闭文件
fclose(pFile);
pFile = NULL;
return nCode;
}
catch(...)
{
if(NULL != pFile)
{
fclose(pFile);
pFile = NULL;
}
EPRINT("downloadFile api exception(%d)\n", errno);
return -1; //接口异常
}
}
/*
* 从文件中读取内容post出去
* 参数1:文件名
* 参数2:返回数据
* 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int ClusterCurl::uploadFileContent(const std::string& sFileName, const int nFormat, std::string& sRec)
{
CURLcode res = CURLE_OK;
FILE* pFile = NULL;
struct stat file_info;
curl_off_t fsize;
int nCode = 0;
try
{
if(sFileName.empty())
{
EPRINT("uploadFileContent filename is empty\n");
return -1; //文件名为空
}
if(stat((char*)sFileName.c_str(), &file_info)) //文件大小
{
EPRINT("uploadFileContent get file info error(%d), %s\n", errno, (char*)sFileName.c_str());
return -1;
}
fsize = (curl_off_t)file_info.st_size;
pFile = fopen((char*)sFileName.c_str(), "rb"); //打开文件,返回结果用文件存储
if (NULL == pFile)
{
EPRINT("uploadFileContent open file error(%d), %s\n", errno, (char*)sFileName.c_str());
return -1; //打开文件失败
}
//设定传输方式
curl_easy_setopt(this->m_pCurl, CURLOPT_POST, 1);
//CURL公共操作方式
nCode = messagePublicMethod(nFormat);
if(0 != nCode)
{
if(NULL != pFile)
{
fclose(pFile);
pFile = NULL;
}
EPRINT("uploadFileContent call messagePublicMethod error(%d) \n", errno);
return -1;
}
// 设置回调函数
curl_easy_setopt(this->m_pCurl, CURLOPT_READFUNCTION, httpReadFile);
curl_easy_setopt(this->m_pCurl, CURLOPT_READDATA, pFile);
curl_easy_setopt(this->m_pCurl, CURLOPT_POSTFIELDSIZE, (curl_off_t)fsize);
sRec = ""; //清空数据
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEFUNCTION, httpDataWriter);
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEDATA, (void*)&sRec);
res = curl_easy_perform(this->m_pCurl);
//处理curl返回值
nCode = dealResCode(res);
if(0 > nCode)
{
EPRINT("deal response code error \n");
}
//关闭文件
fclose(pFile);
pFile = NULL;
return nCode;
}
catch(...)
{
if(NULL != pFile)
{
fclose(pFile);
pFile = NULL;
}
EPRINT("uploadFileContent api exception(%d)\n", errno);
return -1; //接口异常
}
}
/*
* 宏定义上传文件相关信息
*/
#define FILE_NAME_MAX_SIZE (128)
/*
* 从文件全路径中获取文件名指针
* 返回文件名地址
*/
const char* ClusterCurl::getFileName(const char *path)
{
if(!path)
{
return NULL;
}
//找最后一个斜杠/
const char *pname = strrchr(path, '/');
if(!pname)
{
//没找到斜杠,则认为path就是文件名
return path;
}
//找到最后一个斜杠, 反回指针加1
return (char*)(pname + 1);
}
/*
* 上传文件
* 参数1:文件名
* 参数2:返回数据
* 返回值int, 0表示成功, 1表示超时,其他表示失败
*/
int ClusterCurl::uploadFile(const std::string& sFileFullname, std::string& sRec)
{
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:";
try
{
if(sFileFullname.empty())
{
EPRINT("uploadFile sFileFullname is empty\n");
return -1; //文件名为空
}
//获取文件名
const char* pFileName = getFileName(sFileFullname.c_str());
if(NULL == pFileName || '\0' == pFileName[0])
{
EPRINT("uploadFileContent call getFileName failure, sFileFullname=%s \n", sFileFullname.c_str());
return -1;
}
DPRINT("uploadFile pFileName=%s \n", pFileName);
//CURL公共操作方式
nCode = messagePublicMethod(FORMAT_DEFAULT);
if(0 != nCode)
{
EPRINT("uploadFile call messagePublicMethod error(%d) \n", errno);
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, sFileFullname.c_str(),
CURLFORM_END);
/* Fill in the filename field */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "filename",
CURLFORM_COPYCONTENTS, pFileName,
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(this->m_pCurl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(this->m_pCurl, CURLOPT_HTTPPOST, formpost);
//返回值
sRec = ""; //清空数据
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEFUNCTION, httpDataWriter);
curl_easy_setopt(this->m_pCurl, CURLOPT_WRITEDATA, (void*)&sRec);
/* Perform the request, res will get the return code */
res = curl_easy_perform(this->m_pCurl);
/* 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(res);
if(0 > nCode)
{
EPRINT("deal response code error \n");
}
return nCode;
}
catch(...)
{
if(NULL != formpost)
{
curl_formfree(formpost);
formpost = NULL;
}
if( NULL != headerlist)
{
curl_slist_free_all (headerlist);
headerlist = NULL;
}
EPRINT("uploadFile api exception(%d)\n", errno);
return -1; //接口异常
}
}
/*
* main.cpp
*/
#include <stdio.h>
#include <string>
#include "manager_curl.h"
//for test
#define EPRINT printf
#define DPRINT printf
/*
* 通过get 、delete方式发送数据
* 返回值int, 0表示成功,1表示超时, 其它表示失败
*/
int curl_get_message()
{
int nCode = -1;
std::string sIP = "10.200.0.225";
unsigned int nPort = 80;
std::string sUser = "USER"; //可为空
std::string sPwd = "PWD"; //可为空
//这边用智能指针更好
ClusterCurl* pCluster_Curl = new ClusterCurl(sIP, nPort, sUser, sPwd);
if(NULL == pCluster_Curl)
{
//创建Curl对象失败
EPRINT("new object failure!!!!!\n");
return -1;
}
//curl初始化
nCode = pCluster_Curl->initCurlResource();
if(0 != nCode)
{
EPRINT("curl init failure!!!!!\n");
delete pCluster_Curl;
pCluster_Curl = NULL;
return -1;
}
//设置路径
std::string sUrlPath = "/index.html?user=user&name=name";
pCluster_Curl->setUrlPath(sUrlPath);
//发送方式为get,数据格式为默认,内容为空
int nMethod = METHOD_GET;
//int nMethod = METHOD_DELETE;
int nFormat = FORMAT_DEFAULT;
std::string sMsg;
std::string sRec;
nCode = pCluster_Curl->sendMsg(sMsg, nMethod, nFormat,sRec);
printf("%d\n", nCode);
printf("%s\n", sRec.c_str());
delete pCluster_Curl;
return nCode;
}
/*
* 通过post 、put方式发送数据
* 返回值int, 0表示成功,1表示超时, 其它表示失败
*/
int curl_post_message()
{
int nCode = -1;
std::string sIP = "10.200.0.225";
unsigned int nPort = 80;
std::string sUser = "USER"; //可为空
std::string sPwd = "PWD"; //可为空
//这边用智能指针更好
ClusterCurl* pCluster_Curl = new ClusterCurl(sIP, nPort, sUser, sPwd);
if(NULL == pCluster_Curl)
{
//创建Curl对象失败
printf("new object failure!!!!!\n");
return -1;
}
//curl初始化
nCode = pCluster_Curl->initCurlResource();
if(0 != nCode)
{
EPRINT("curl init failure!!!!!\n");
delete pCluster_Curl;
pCluster_Curl = NULL;
return -1;
}
//设置路径
std::string sUrlPath = "/index.html";
pCluster_Curl->setUrlPath(sUrlPath);
//发送方式为post,数据格式为json,发送数据为json
int nMethod = METHOD_POST;
//int nMethod = METHOD_PUT;
int nFormat = FORMAT_JSON;
std::string sRec;
std::string sMsg = "{";
sMsg += "\"UserName\":\"user\",";
sMsg += "\"UserPwd\":\"pwd\"";
sMsg += "}";
nCode = pCluster_Curl->sendMsg(sMsg, nMethod, nFormat,sRec);
printf("%d\n", nCode);
delete pCluster_Curl;
return nCode;
}
/*
* 上传文件
* 返回值int, 0表示成功,1表示超时, 其它表示失败
*/
int curl_upload_file()
{
int nCode = -1;
std::string sIP = "10.200.0.225";
unsigned int nPort = 80;
std::string sUser = "USER"; //可为空
std::string sPwd = "PWD"; //可为空
//这边用智能指针更好
ClusterCurl* pCluster_Curl = new ClusterCurl(sIP, nPort, sUser, sPwd);
if(NULL == pCluster_Curl)
{
//创建Curl对象失败
printf("new object failure!!!!!\n");
return -1;
}
//curl初始化
nCode = pCluster_Curl->initCurlResource();
if(0 != nCode)
{
EPRINT("curl init failure!!!!!\n");
delete pCluster_Curl;
pCluster_Curl = NULL;
return -1;
}
//设置路径
std::string sUrlPath = "";
pCluster_Curl->setUrlPath(sUrlPath);
//上传文件名
std::string sFileName = "./b.zip";
std::string sRec;
nCode = pCluster_Curl->uploadFile(sFileName, sRec);
printf("%d\n", nCode);
printf("%s\n", sRec.c_str());
delete pCluster_Curl;
return nCode;
}
/*
* 下载文件
* 返回值int, 0表示成功,1表示超时, 其它表示失败
*/
int curl_download_file()
{
int nCode = -1;
std::string sIP = "10.200.0.225";
unsigned int nPort = 80;
std::string sUser = "USER"; //可为空
std::string sPwd = "PWD"; //可为空
//这边用智能指针更好
ClusterCurl* pCluster_Curl = new ClusterCurl(sIP, nPort, sUser, sPwd);
if(NULL == pCluster_Curl)
{
//创建Curl对象失败
printf("new object failure!!!!!\n");
return -1;
}
//curl初始化
nCode = pCluster_Curl->initCurlResource();
if(0 != nCode)
{
EPRINT("curl init failure!!!!!\n");
delete pCluster_Curl;
pCluster_Curl = NULL;
return -1;
}
//设置路径
std::string sUrlPath = "";
pCluster_Curl->setUrlPath(sUrlPath);
//下载文件名
std::string sFileName = "./test.html";
int nFormat = FORMAT_JSON;
nCode = pCluster_Curl->downloadFile(sFileName, nFormat);
printf("%d\n", nCode);
delete pCluster_Curl;
return nCode;
}
/*
* curl使用方式
* 1.curl全局资源初始化,放在主线程中
* 2.创建curl对象,进行curl参数初始化
* 3.调用发送数据函数sendMsg,上传文件函数uploadFile,下载文件函数downloadFile
* 4.curl全局资源清除,放在主线程中
*/
int main()
{
//全局资源初始化,放在主线程
ClusterCurl::globalInit();
//发送数据操作
//curl_get_message();
//curl_post_message();
//上传,下载操作
//curl_download_file();
curl_upload_file();
//全局资源清除,放在主线程中
ClusterCurl::globalCleanup();
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 = g++
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