由于项目需求需要发送http_post去请求数据,所以上网去寻找了一些发送http请求的方法,发现libcurl较为常用,然后根据官网上的例子,对libcurl做了一些简单的封装,支持多线程,并且有进度条显示,希望对大家有帮助,如有发现问题,欢迎批评指正~
代码(libcurl_http.h)如下:
#pragma once
#include "curl/curl.h"
#include <time.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <string>
using namespace std;
#define error(args) do{ \
printf("[%s] - %s:%s:%d-----%s, %s\n" , "error", __FILE__, __FUNCTION__, __LINE__, strerror(errno), args); \
} while(0)
namespace INTERNET_SERVICE {
class curl_http_send
{
public:
curl_http_send();
~curl_http_send();
// desc: 每次接收数据内容的回调函数(当数据长度长的时候,未必能一次接收成功)
// param: contents/数据内容 size/每个元素的大小 nmemb/元素的个数 pcurl/为用户自定义指针
// return: 接收数据的总数
static size_t receive_data(void * contents, size_t size, size_t nmemb, void *pcurl);
// desc: 上传下载进度的回调函数
// param: clientp/为用户自定义指针 dltotal/为需要下载的总数 dlnow/当前下载的总数 ultotal/为需要上传的总数 ulnow/当前上传的总数
// return: 返回0,此函数返回非0值将会中断传输
static int progress_callback(void * clientp,double dltotal,double dlnow,double ultotal,double ulnow);
// desc: 接收报头数据的回调函数
// param: buffer/数据内容 size/每个元素的大小 nitems/元素的个数 userdata/为用户自定义指针
// return: 接收报头数据的总数
static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata);
// desc: httpget请求
// param: strUrl/申请数据的地址 nTimeout/超时时间
// return: 返回数据
string HttpGet(const std::string & strUrl, const long nTimeout=10);
// desc: httppost请求
// param: strUrl/申请数据的地址 send_data/发送的数据 nTimeout/超时时间
// return: 返回数据
string HttpPost(const std::string & strUrl, const char * send_data, const long nTimeout=10);
private:
curl_http_send(curl_http_send &&);
curl_http_send(const curl_http_send &);
curl_http_send &operator=(curl_http_send &&);
curl_http_send &operator=(const curl_http_send &);
private:
volatile double buf_size; //接收到数据的总大小
string data; //接收到数据
};
}
代码(libcurl_http.cpp)如下:
#include "curl_http_post.h"
#include <stdlib.h>
#include <string.h>
namespace INTERNET_SERVICE {
curl_http_send::curl_http_send():buf_size(0){
}
curl_http_send::~curl_http_send()
{
}
size_t curl_http_send::receive_data(void * contents, size_t size, size_t nmemb, void *pcurl)
{
FILE *f_p;
curl_http_send *curl_p = (curl_http_send *)pcurl;
//将接收到数据写到data.txt中记录
f_p = fopen("data.txt", "a+");
if (!f_p) {
error("data.txt open failure\n");
}
fwrite(contents, size*nmemb, 1, f_p);
fclose(f_p);
//将接收到的数据写入data中
curl_p->data.append((char*)contents, size * nmemb);
return size * nmemb;
}
int curl_http_send::progress_callback(void * clientp, double dltotal, double dlnow, double ultotal, double ulnow)
{
curl_http_send *curl_p = (curl_http_send *)clientp;
if(curl_p->buf_size)
printf("\r[%u%%]", (unsigned int)((dlnow / curl_p->buf_size) * (double)100));
return 0;
}
size_t curl_http_send::header_callback(char *buffer, size_t size, size_t nitems, void *userdata) {
curl_http_send *curl_p = (curl_http_send *)userdata;
//在报头中获取数据的总长度
char *buf = NULL;
char *buf_right = NULL;
buf = strtok_s(buffer, ":", &buf_right);
//将此次读取要读的长度获取出来,用于设置进度条
if (!strncmp("data-length", buf, sizeof("data-length"))) {
curl_p->buf_size = strtod(buf_right, NULL);
}
return size * nitems;
}
string curl_http_send::HttpGet(const std::string & strUrl, const long nTimeout)
{
data.clear();
CURLcode res;
CURL* pCURL = curl_easy_init();
if (!pCURL) {
error("curl_easy_init error");
curl_easy_cleanup(pCURL);
return "";
}
//设置url
curl_easy_setopt(pCURL, CURLOPT_URL, strUrl.c_str());
//设置不忽略SIGPIPE信号
curl_easy_setopt(pCURL, CURLOPT_NOSIGNAL, 1L);
//设置超时
curl_easy_setopt(pCURL, CURLOPT_TIMEOUT, nTimeout);
//设置开启进度条
curl_easy_setopt(pCURL, CURLOPT_NOPROGRESS, 0L);
//设置用于接收数据的回调函数
curl_easy_setopt(pCURL, CURLOPT_WRITEFUNCTION, curl_http_send::receive_data);
//设置传递给接收函数的自定义指针
curl_easy_setopt(pCURL, CURLOPT_WRITEDATA, this);
//设置用于进度显示的回调函数
curl_easy_setopt(pCURL, CURLOPT_PROGRESSFUNCTION, curl_http_send::progress_callback);
//设置传递给进度显示函数的自定义指针
curl_easy_setopt(pCURL, CURLOPT_PROGRESSDATA, this);
//设置用于接收报头数据的回调函数
curl_easy_setopt(pCURL, CURLOPT_HEADERFUNCTION, curl_http_send::header_callback);
//设置传递给接收报头函数的自定义指针
curl_easy_setopt(pCURL, CURLOPT_HEADERDATA, this);
//发送数据
res = curl_easy_perform(pCURL);
//如果res != CURLE_OK则发送失败
if (res != CURLE_OK) {
error("curl_easy_perform error");
data.clear();
}
else {
//获取接收到的数据Status,如果为200则表示接收发正常,其余则不正常
long response_code;
curl_easy_getinfo(pCURL, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code == 200) {
printf("Data status normal\n");
}
else {
printf("Data status abnormal\n");
}
}
curl_easy_cleanup(pCURL);
return data;
}
string curl_http_send::HttpPost(const std::string & strUrl, const char * send_data, const long nTimeout)
{
data.clear();
CURLcode res;
CURL* pCURL = curl_easy_init();
struct curl_slist* headers = NULL;
if (!pCURL) {
error("curl_easy_init error");
curl_easy_cleanup(pCURL);
return "";
}
this->buf_size = 0;
CURLcode ret;
ret = curl_easy_setopt(pCURL, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(pCURL, CURLOPT_TIMEOUT, 10);
ret = curl_easy_setopt(pCURL, CURLOPT_POST, 1L);
//设置发送的数据为json数据
headers = curl_slist_append(headers, "content-type:application/json");
if (headers == NULL) {
curl_slist_free_all(headers);
error("curl_slist_append error");
return "";
}
//设置要http头信息
ret = curl_easy_setopt(pCURL, CURLOPT_HTTPHEADER, headers);
//设置不忽略SIGPIPE信号
curl_easy_setopt(pCURL, CURLOPT_NOSIGNAL, 1L);
//设置开启进度条
curl_easy_setopt(pCURL, CURLOPT_NOPROGRESS, 0L);
//设置要发送的数据
ret = curl_easy_setopt(pCURL, CURLOPT_POSTFIELDS, send_data);
//设置超时
ret = curl_easy_setopt(pCURL, CURLOPT_TIMEOUT, nTimeout);
//设置用于接收数据内容的回调函数
ret = curl_easy_setopt(pCURL, CURLOPT_WRITEFUNCTION, curl_http_send::receive_data);
//设置传递给接收函数内容的自定义指针
ret = curl_easy_setopt(pCURL, CURLOPT_WRITEDATA, this);
//设置用于进度显示的回调函数
ret = curl_easy_setopt(pCURL, CURLOPT_PROGRESSFUNCTION, curl_http_send::progress_callback);
//设置传递给进度显示函数的自定义指针
ret = curl_easy_setopt(pCURL, CURLOPT_PROGRESSDATA, this);
//设置用于接收报头数据的回调函数
ret = curl_easy_setopt(pCURL, CURLOPT_HEADERFUNCTION, curl_http_send::header_callback);
//设置传递给接收报头函数的自定义指针
ret = curl_easy_setopt(pCURL, CURLOPT_HEADERDATA, this);
res = curl_easy_perform(pCURL);
curl_slist_free_all(headers);
//如果res != CURLE_OK则发送失败
if (res != CURLE_OK) {
error("curl_easy_perform error");
data.clear();
}
else {
//获取接收到的数据Status,如果为200则表示接收发正常,其余则不正常
long response_code;
curl_easy_getinfo(pCURL, CURLINFO_RESPONSE_CODE, &response_code);
char *contentType = { 0 };
CURLcode return_code;
return_code = curl_easy_getinfo(pCURL, CURLINFO_CONTENT_TYPE, &contentType);
if ((CURLE_OK == return_code) && contentType)
cout << "请求的文件类型:" << contentType << endl;
if (response_code == 200) {
printf("Data status normal\n");
}
else {
printf("Data status abnormal\n");
}
}
curl_easy_cleanup(pCURL);
return data;
}
}
代码(main.cpp)如下:
#include "curl_http_post.h"
#include <fstream>
#include <windows.h>
#include <pthread.h>
#define URL "http://xxx" //目标url
#define OVER_TIME 500 //超时时间
//将Unicode的字符串转成UTF-8的字符串
static std::string GBKToUTF8(const char* strGBK)
{
int len = MultiByteToWideChar(CP_ACP, 0, strGBK, -1, NULL, 0);
wchar_t* wstr = new wchar_t[len + 1];
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_ACP, 0, strGBK, -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char[len + 1];
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
std::string strTemp = str;
if (wstr) delete[] wstr;
if (str) delete[] str;
return strTemp;
}
//多线程测试
void * thread_run_function(void *ptr) {
printf("thread_run_function\n");
INTERNET_SERVICE::curl_http_send *p = new INTERNET_SERVICE::curl_http_send();
string str2 = GBKToUTF8("{\"standardId\": \"1191537941206355970\",\"attachedInformation\": \"ncdisp\"}");
string data = p->HttpPost(URL, str2.c_str(), OVER_TIME);
char filename[20];
sprintf(filename, "%s%u%s", "data", *(int *)ptr, ".txt");
//将返回的结果写到对应的线程编号的文件中保存
FILE *fp = fopen(filename, "w");
fwrite(data.c_str(), data.size(), 1, fp);
fclose(fp);
fp = NULL;
delete p;
return NULL;
}
int main() {
curl_global_init(CURL_GLOBAL_ALL);
INTERNET_SERVICE::curl_http_send *p = new INTERNET_SERVICE::curl_http_send();
pthread_t thread1, thread2,thread3, thread4;
unsigned int index1 = 1, index2 = 2, index3 = 3, index4 = 4;
pthread_create(&thread1, NULL, thread_run_function, &index1);
pthread_create(&thread2, NULL, thread_run_function, &index2);
pthread_create(&thread3, NULL, thread_run_function, &index3);
pthread_create(&thread4, NULL, thread_run_function, &index4);
//http_get
cout << "return data-> " << p->HttpGet("www.baidu.com") << endl;
//http_post
string str2 = GBKToUTF8("{\"standardId\": \"1191537941206355970\",\"attachedInformation\": \"ncdisp\"}");
cout << "return data-> " << p->HttpPost(URL, str1.c_str(), OVER_TIME) << endl;
void *aaa;
pthread_join(thread1,&aaa);
pthread_join(thread2,&aaa);
pthread_join(thread3,&aaa);
pthread_join(thread4,&aaa);
delete p;
curl_global_cleanup();
system("pause");
return 0;
}
参考:
1.https://curl.haxx.se/libcurl/c/
2.https://blog.csdn.net/FK2016/article/details/82226683