最近嵌軟同事想接入第三方廠商的設備,在寫客戶端和服務端,用curl通信消息一直髮不過去,或者遇到頭和消息體如何分開獲取等問題。我就給他這個代碼了。基於這個他總算完成了基本的通信功能
curl本身的代碼庫自行去獲取吧都差不多的不用糾結,下面是封裝curl的一個頭文件和一個源文件,把他們加到你的工程就可以使用了
//HttpCurl.h
#pragma once
#include <string>
#include <map>
#include <list>
#include "curl/curl.h"
#include <algorithm>
#include <xfunctional>
class CHttpCurl
{
public:
typedef std::map<std::string, std::string> headermap;
/** response struct for queries */
typedef struct
{
int ncode;
std::string strBody;
headermap mapHeaders;
} response;
/** struct used for uploading data */
typedef struct
{
const char* pData;
size_t length;
} upload_object;
/** struct used for multipart/form-data upload*/
typedef struct
{
std::string strCopyName;
std::string strFileName;
std::string strData;
} FileUpLoad_obj;
private:
CHttpCurl();
public:
~CHttpCurl();
static CHttpCurl* GetInstance();
// Auth
void setAuth(const std::string& user, const std::string& password);
void clearAuth();
// HTTP GET
response get(const std::string& url, const bool bCheckCertificate = false);
// HTTP GET
response get(const std::string& url, const std::string& ctypeHeader);
// HTTP GET
response get(const std::string& url, const std::list<std::string> & ctypeList);
// HTTP POST
response post(const std::string& url, const std::string& ctype,
const std::string& data);
// HTTP POST
response post(const std::string& url, const std::list<std::string> & ctypeList,
const std::string& data, const bool bCheckCertificate = true);
// HTTP POST FOR FILE UPLOAD
response post(const std::string& url,
const std::list<std::string> & ctypeList,
const std::list<FileUpLoad_obj> & fileInfo,
const std::list<FileUpLoad_obj> & CopyContent);
// HTTP PUT
response put(const std::string& url, const std::list<std::string> & ctypeList,
const std::string& data);
// HTTP DELETE
response curlDelete(const std::string& url, const std::list<std::string> & ctypeList);
private:
const char * m_pUser_Agent;
std::string m_strUser_Pass;
void Set_CurlPublicOpt(CURL *pCurl, const std::string& strUrl, CHttpCurl::response & ret);
// writedata callback function
static size_t write_callback(void *ptr, size_t size, size_t nmemb,
void *userdata);
// header callback function
static size_t header_callback(void *ptr, size_t size, size_t nmemb,
void *userdata);
// read callback function
static size_t read_callback(void *ptr, size_t size, size_t nmemb,
void *userdata);
// trim from start
static inline std::string <rim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(::isspace))));
return s;
}
// trim from end
static inline std::string &rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(::isspace))).base(), s.end());
return s;
}
// trim from both ends
static inline std::string &trim(std::string &s) {
return ltrim(rtrim(s));
}
};
//HttpCurl.cpp
#include "HttpCurl.h"
#include <functional>
#pragma comment(lib, "curl/libcurl.lib")
CHttpCurl::CHttpCurl()
:m_pUser_Agent("")
{
curl_global_init(CURL_GLOBAL_ALL);
}
CHttpCurl::~CHttpCurl()
{
curl_global_cleanup();
}
CHttpCurl* CHttpCurl::GetInstance()
{
static CHttpCurl s_Curl;
return &s_Curl;
}
void CHttpCurl::setAuth(const std::string& user, const std::string& password)
{
m_strUser_Pass.clear();
m_strUser_Pass += user + ":" + password;
}
void CHttpCurl::clearAuth()
{
m_strUser_Pass.clear();
}
/**
* @brief HTTP GET method
*
* @param url to query
*
* @return response struct
*/
CHttpCurl::response CHttpCurl::get(const std::string& url, const bool bCheckCertificate)
{
/** create return struct */
CHttpCurl::response ret = {};
// use libcurl
CURL *curl = nullptr;
CURLcode res = CURLE_OK;
curl = curl_easy_init();
if (curl)
{
Set_CurlPublicOpt(curl, url, ret);
if (!bCheckCertificate)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); //設定爲不驗證證書
}
/** perform the actual query */
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
ret.strBody = "Failed to query.";
ret.ncode = -1;
return ret;
}
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
ret.ncode = static_cast<int>(http_code);
curl_easy_cleanup(curl);
}
return ret;
}
CHttpCurl::response CHttpCurl::get(const std::string& url, const std::string& ctypeHeader)
{
/** create return struct */
CHttpCurl::response ret = {};
// use libcurl
CURL *curl = nullptr;
CURLcode res = CURLE_OK;
curl = curl_easy_init();
if (curl)
{
Set_CurlPublicOpt(curl, url, ret);
//method設爲GET
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
/** set content-type header */
curl_slist* header = NULL;
header = curl_slist_append(header, ctypeHeader.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
/** perform the actual query */
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
ret.strBody = "Failed to query.";
ret.ncode = -1;
return ret;
}
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
ret.ncode = static_cast<int>(http_code);
curl_easy_cleanup(curl);
}
return ret;
}
CHttpCurl::response CHttpCurl::get(const std::string& url, const std::list<std::string> & ctypeList)
{
/** create return struct */
CHttpCurl::response ret = {};
// use libcurl
CURL *curl = nullptr;
CURLcode res = CURLE_OK;
curl = curl_easy_init();
if (curl)
{
Set_CurlPublicOpt(curl, url, ret);
//method設爲GET
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
/** set content-type header */
curl_slist* header = nullptr;
for (auto & item : ctypeList)
{
header = curl_slist_append(header, item.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
/** perform the actual query */
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
ret.strBody = "Failed to query.";
ret.ncode = -1;
return ret;
}
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
ret.ncode = static_cast<int>(http_code);
curl_easy_cleanup(curl);
}
return ret;
}
/**
* @brief HTTP POST method
*
* @param url to query
* @param ctype content type as string
* @param data HTTP POST body
*
* @return response struct
*/
CHttpCurl::response CHttpCurl::post(const std::string& url,
const std::string& ctype,
const std::string& data)
{
/** create return struct */
CHttpCurl::response ret = {};
/** build content-type header string */
std::string ctype_header = "Content-Type: " + ctype + ";";//"; charset=UTF-8";
// use libcurl
CURL *curl = nullptr;
CURLcode res = CURLE_OK;
curl = curl_easy_init();
if (curl)
{
Set_CurlPublicOpt(curl, url, ret);
/** Now specify we want to POST data */
curl_easy_setopt(curl, CURLOPT_POST, 1L);
/** set post fields */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
/** set content-type header */
curl_slist* header = nullptr;
header = curl_slist_append(header, ctype_header.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
/** perform the actual query */
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
ret.strBody = "Failed to query.";
ret.ncode = -1;
return ret;
}
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
ret.ncode = static_cast<int>(http_code);
curl_slist_free_all(header);
curl_easy_cleanup(curl);
}
return ret;
}
CHttpCurl::response CHttpCurl::post(const std::string& url,
const std::list<std::string> & ctypeList,
const std::string& data,
const bool bCheckCertificate)
{
/** create return struct */
CHttpCurl::response ret = {};
// use libcurl
CURL *curl = nullptr;
CURLcode res = CURLE_OK;
curl = curl_easy_init();
if (curl)
{
Set_CurlPublicOpt(curl, url, ret);
/** Now specify we want to POST data */
curl_easy_setopt(curl, CURLOPT_POST, 1L);
/** set post fields */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
/** set content-type header */
curl_slist* header = nullptr;
for (auto & item : ctypeList)
{
header = curl_slist_append(header, item.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
if (!bCheckCertificate)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); //設定爲不驗證證書
}
/** perform the actual query */
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
ret.strBody = "Failed to query.";
ret.ncode = -1;
return ret;
}
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
ret.ncode = static_cast<int>(http_code);
curl_slist_free_all(header);
curl_easy_cleanup(curl);
}
return ret;
}
CHttpCurl::response CHttpCurl::post(const std::string& url,
const std::list<std::string> & ctypeList,
const std::list<FileUpLoad_obj> & fileInfo,
const std::list<FileUpLoad_obj> & CopyContent)
{
CHttpCurl::response ret = {};
// use libcurl
CURL *curl = nullptr;
CURLcode res = CURLE_OK;
curl = curl_easy_init();
if (curl)
{
Set_CurlPublicOpt(curl, url, ret);
/** Now specify we want to POST data */
curl_easy_setopt(curl, CURLOPT_POST, 1L);
/** set content-type header */
curl_slist* header = nullptr;
for (auto & item : ctypeList)
{
header = curl_slist_append(header, item.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_httppost* pFormPost = NULL;
curl_httppost* pLastElem = NULL;
for (auto & item : fileInfo)
{
curl_formadd(&pFormPost, &pLastElem,
CURLFORM_COPYNAME, item.strCopyName.c_str(),
CURLFORM_BUFFER, item.strFileName.c_str(),
CURLFORM_BUFFERPTR, item.strData.c_str(),
CURLFORM_BUFFERLENGTH, item.strData.length(),
CURLFORM_END);
}
for (auto & item : CopyContent)
{
curl_formadd(&pFormPost, &pLastElem,
CURLFORM_COPYNAME, item.strCopyName.c_str(),
CURLFORM_COPYCONTENTS, item.strData.c_str(),
CURLFORM_END);
}
curl_easy_setopt(curl, CURLOPT_HTTPPOST, pFormPost);
/** perform the actual query */
res = curl_easy_perform(curl);
curl_formfree(pFormPost);
if (res != CURLE_OK)
{
ret.strBody = "Failed to query.";
ret.ncode = -1;
return ret;
}
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
ret.ncode = static_cast<int>(http_code);
curl_slist_free_all(header);
curl_easy_cleanup(curl);
}
return ret;
}
CHttpCurl::response CHttpCurl::put(const std::string& url, const std::list<std::string> & ctypeList,
const std::string& data)
{
/** create return struct */
CHttpCurl::response ret = {};
// use libcurl
CURL *curl = nullptr;
CURLcode res = CURLE_OK;
curl = curl_easy_init();
if (curl)
{
Set_CurlPublicOpt(curl, url, ret);
//curl_easy_setopt(curl, CURLOPT_PUT, 1L); //沒用
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
/** set post fields */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
/** set content-type header */
curl_slist* header = nullptr;
for (auto & item : ctypeList)
{
header = curl_slist_append(header, item.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
/** perform the actual query */
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
ret.strBody = "Failed to query.";
ret.ncode = -1;
return ret;
}
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
ret.ncode = static_cast<int>(http_code);
curl_slist_free_all(header);
curl_easy_cleanup(curl);
}
return ret;
}
CHttpCurl::response CHttpCurl::curlDelete(const std::string& url, const std::list<std::string> & ctypeList)
{
/** create return struct */
CHttpCurl::response ret = {};
// use libcurl
CURL *curl = nullptr;
CURLcode res = CURLE_OK;
curl = curl_easy_init();
if (curl)
{
Set_CurlPublicOpt(curl, url, ret);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
/** set content-type header */
curl_slist* header = nullptr;
std::string strTemp;
for (auto & item : ctypeList)
{
header = curl_slist_append(header, item.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
/** perform the actual query */
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
ret.strBody = "Failed to query.";
ret.ncode = -1;
return ret;
}
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
ret.ncode = static_cast<int>(http_code);
curl_slist_free_all(header);
curl_easy_cleanup(curl);
}
return ret;
}
void CHttpCurl::Set_CurlPublicOpt(CURL *pCurl, const std::string& strUrl, CHttpCurl::response & ret)
{
if (pCurl)
{
/** set basic authentication if present*/
if (m_strUser_Pass.length() > 0){
curl_easy_setopt(pCurl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(pCurl, CURLOPT_USERPWD, m_strUser_Pass.c_str());
}
/** set user agent */
curl_easy_setopt(pCurl, CURLOPT_USERAGENT, m_pUser_Agent);
/** set query URL */
curl_easy_setopt(pCurl, CURLOPT_URL, strUrl.c_str());
/** set callback function */
curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION,CHttpCurl::write_callback);
/** set data object to pass to callback function */
curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &ret);
/** set the header callback function */
curl_easy_setopt(pCurl, CURLOPT_HEADERFUNCTION,CHttpCurl::header_callback);
/** callback object for headers */
curl_easy_setopt(pCurl, CURLOPT_HEADERDATA, &ret);
//連接超時時間
curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 20);
curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 6);
}
}
size_t CHttpCurl::write_callback(void *data, size_t size, size_t nmemb,
void *userdata)
{
CHttpCurl::response* r;
r = reinterpret_cast<CHttpCurl::response*>(userdata);
r->strBody.append(reinterpret_cast<char*>(data), size*nmemb);
return (size * nmemb);
}
/**
* @brief header callback for libcurl
*
* @param data returned (header line)
* @param size of data
* @param nmemb memblock
* @param userdata pointer to user data object to save headr data
* @return size * nmemb;
*/
size_t CHttpCurl::header_callback(void *data, size_t size, size_t nmemb,
void *userdata)
{
CHttpCurl::response* r;
r = reinterpret_cast<CHttpCurl::response*>(userdata);
std::string header(reinterpret_cast<char*>(data), size*nmemb);
size_t seperator = header.find_first_of(":");
if (std::string::npos == seperator) {
//roll with non seperated headers...
trim(header);
if (0 == header.length()){
return (size * nmemb); //blank line;
}
r->mapHeaders[header] = "present";
}
else {
std::string key = header.substr(0, seperator);
trim(key);
std::string value = header.substr(seperator + 1);
trim(value);
r->mapHeaders[key] = value;
}
return (size * nmemb);
}
/**
* @brief read callback function for libcurl
*
* @param pointer of max size (size*nmemb) to write data to
* @param size size parameter
* @param nmemb memblock parameter
* @param userdata pointer to user data to read data from
*
* @return (size * nmemb)
*/
size_t CHttpCurl::read_callback(void *data, size_t size, size_t nmemb,
void *userdata)
{
/** get upload struct */
CHttpCurl::upload_object* u;
u = reinterpret_cast<CHttpCurl::upload_object*>(userdata);
/** set correct sizes */
size_t curl_size = size * nmemb;
size_t copy_size = (u->length < curl_size) ? u->length : curl_size;
/** copy data to buffer */
memcpy(data, u->pData, copy_size);
/** decrement length and increment data pointer */
u->length -= copy_size;
u->pData += copy_size;
/** return copied size */
return copy_size;
}