c/c++使用libcurl库做http客户端及封装(HTTP_GET和HTTP_POST)

2023-05-16

由于项目需求需要发送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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c/c++使用libcurl库做http客户端及封装(HTTP_GET和HTTP_POST) 的相关文章

随机推荐

  • 工业相机的术语相关

    一 工业相机术语 像素 xff08 pixel xff09 xff1a 图像上的最小组成单元 图像由小方格即像素组成的 xff0c 这些小方块都有一个明确的位置和被分配的色彩数值 xff0c 小方格颜色和位置就决定该图像所呈现出来的样子 像
  • C++学习笔记(二)

    1 C 43 43 简介 参考C 43 43 菜鸟教程 C 43 43 是一种静态的编译式的通用的大小写敏感的不规则的编程语言 xff0c 支持过程编程 对象编程和泛型编程 C 43 43 综合了高级语言和低级语言的特点 xff0c 是一种
  • Ubuntu 16.04 ifconfig输出ens33,不能联网问题的解决

    VM 12 0 ubuntu 16 04 问题 xff1a 在NAT模式下联网的设置见前一个博文 xff0c 又在同一台电脑下安装ubuntun16 04虚拟机 xff0c 不能联网 xff0c 用ifconfig时输出如下 xff1a 并
  • C++:internal compiler error解决

    编绎文件时 xff0c 出现这个问题原因一般就是内存不够 xff0c 若是在虚拟机上 xff0c 关掉虚拟机 xff0c 可直接调节虚拟机内存大小 xff0c 然后重新启动即可
  • Error: Could not find the following Boost libraries:boost_serialization

    Boost 1 59 0 CMake 3 7 2 使用CMake编译时出现以下错误 xff1a 无法找到以下库 xff0c 但是编译好的库中是有libboost serialization libboost system等这些文件的 xff
  • ubuntu下make时对XX未定义的引用

    Q1 库对XX未定义的引用 xff0c 如 xff1a Thirdparty vio g2o lib libvio g2o so xff1a 对 39 IMUErrorModel lt ceres Jet lt double 38 gt g
  • Birch算法介绍

    目录 前言 一 Birch算法基本思想 二 聚类特征CF和CF 树 1 聚类特征CF 2 CF tree 3 CF tree 的生成 三 Birch算法流程 1 birch算法的优化 2 算法优缺点 四 算法实验实例 1 研究不指定簇数的情
  • [转]伪代码的写法

    伪代码的写法 xff08 附 xff1a 12种排序算法详解 xff09 转自 xff1a http blog sina com cn s blog 134451adb0102wfgu html 伪代码 xff08 Pseudocode x
  • linux C++调用python3的程序

    环境 xff1a ubuntu1404 python3 4 3 首先安装对应python不同版本的调用库 sudo apt get install python3 4 dev xff0c python脚本基本不用变 xff0c 在C 43
  • Bug 记录

    Bug记录 CocosCreator打包出现 Error xff1a Program type already present android support v4 os ResultReceiver MyResultReceiver 解决
  • I2C通信

    I2 C 芯片间 总线接口连接微控制器和串行 I 2 C 总线 它提供多主机功能 xff0c 控制所有 I 2 C 总线特定的 时序 协议 仲裁和定时 1 xff0c 物理层 1 IIC是一种两线串行的通信方式 xff0c SCL xff0
  • 使用Mybatis-Plus代码生成器的报错解决

    使用Mybatis Plus的同学 xff0c 在使用代码生成器的时候不知道有没有遇到过这个问题 xff1a 21 36 23 829 main DEBUG com baomidou mybatisplus generator AutoGe
  • Debian之安装完成后找不到命令解决办法

    1 修改配置文件 bashrc vim root bashrc export PATH 61 PATH usr sbin 2 使配置文件生效 source root bashrc
  • 相机标定、双目相机标定(原理)、三维重建效果展示

    1 相机标定的目的 xff1a xff08 1 xff09 通过单目相机标定分别求出左右相机的内参数和外参数 xff08 2 xff09 矫正由于镜头畸变造成的图片的变形 xff0c 例如 xff0c 现实中的直线 xff0c 拍摄成图像后
  • mac系统做openstack qcow2/raw镜像

    1 vmware安装出来虚拟机 xff08 操作系统不拆分 xff09 2 zhangjinyudeMacBook Pro Asianux vmwarevm zhangjinyu ls lh total 2820216 rw 1 zhang
  • 使用 Chrome 获取 Cookie 的数据

    Chrome 浏览器自带的开发功能相当强大 xff0c 这里只使用它的抓包功能 一 在浏览器中打开目标网站并登录 xff0c 进入目标页面 二 在 Chrome 浏览器下方的开发工具中单击 Network 标签页 按 F5 键 xff0c
  • 后台开发SQL技术总结

    一 字符串截取 1 substring str pos 用法 从字符串的第 4 个字符位置开始取 xff0c 直到结束 mysql gt select substring 39 example com 39 4 43 43 substrin
  • 论文记录:图像描述技术综述

    文章目录 前言 一 什么是image caption xff1f 二 基于深度学习的图像描述方法 1 基于编码器 解码器的方法 2 基于注意力机制的方法 3 基于生成对抗网络的方法 4 基于强化学习的方法 5 基于密集描述的方法 总结 前言
  • 一个接口有多个实现类

    如果一个接口有多个实现类 xff0c 在Controller层注入后调用 xff0c 怎么知道调用的是接口的哪个方法呢 xff1f 经过一番测试 和查找资料 终于找到了结果 2 0一个接口对应多个实现类 一个接口对应对个实现类 xff0c
  • c/c++使用libcurl库做http客户端及封装(HTTP_GET和HTTP_POST)

    由于项目需求需要发送http post去请求数据 xff0c 所以上网去寻找了一些发送http请求的方法 xff0c 发现libcurl较为常用 xff0c 然后根据官网上的例子 xff0c 对libcurl做了一些简单的封装 xff0c