C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)

在网上搜寻各种libcurl的用法,将代码集合于此!


目录

  • 一、配置curl项目
  • 二、案例
    • 1. 使用回调函数将请求到的数据写入文件中
    • 2. 上传文件到FTP
    • 3. curl_formadd - 表单文件上传和上传数据
    • 4. 小插曲 - 验证是否上传成功
    • 5. C++用libcurl通过HTTP以表单的方式Post数据到服务器
    • 6. 使用回调函数文件上传
    • 7. 通过回调函数上传数据
    • 8. curl_formadd - 表单上传多个文件
    • 9. curl_mime_data - 表单上传多个文件
    • 10. 使用多线程上传多个文件
    • 11. 请求下载文件
    • 12. 同时下载多个文件 - 无法实现保存到本地,只能实现下载效果
    • 13. 使用多线程请求下载多个文件
  • 三、总结


一、配置curl项目

  1. 下载curl
    下载链接:https://curl.se/download.html
    C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第1张图片
    下载后解压!

  2. 编译curl库
    依次打开路径,找到vs工程并双击打开!
    C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第2张图片
    C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第3张图片
    右键 - 属性 - 配置属性 - 常规 - Windows SDK 版本 - 选择自己对应的哪个版本
    C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第4张图片
    修改编译为DLL Debug x64
    C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第5张图片

最后右键curl,重新生成即可!
C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第6张图片

生成成功后在项目文件夹中会多出一个build文件夹,其中我们需要的lib就在里面
C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第7张图片

  1. 打开vs创建一个项目
    将include文件夹和libcurld.lib 和 .dll 拷贝到自己新建的项目路径中
    C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第8张图片

    拷贝后开始添加链接库
    C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第9张图片
    C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第10张图片

  2. 测试
    curl :get、pos请求,将请求到的数据写入get.html 和 post.html文件中。

#include 
#include "./include/curl/curl.h"

bool getUrl(const char *filename) {
	CURL *curl;			// CURL void
	CURLcode res;		// CURLcode 枚举
	FILE *fp;
	//if ((fp = fopen(filename, "w")) == NULL)  // 返回结果用文件存储
	//	return false;

	errno_t err = fopen_s(&fp, filename, "w");
	if (err != 0) {
		printf("open file error!\n");
		return false;
	}

	res = curl_global_init(CURL_GLOBAL_ALL);

	struct curl_slist *headers = NULL;
	headers = curl_slist_append(headers, "Accept: Agent-007");
	//headers = curl_slist_append(headers, "Accept:");
	curl = curl_easy_init();    // 初始化
	if (curl) {
		//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");// 代理
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 改协议头
		curl_easy_setopt(curl, CURLOPT_URL, "www.baidu.com");
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); //将返回的html主体数据输出到fp指向的文件
		curl_easy_setopt(curl, CURLOPT_HEADERDATA, fp); //将返回的http头输出到fp指向的文件
		res = curl_easy_perform(curl);   // 执行

		char *cal = curl_version();
		printf("curl_version = %s", cal);

		if (res != 0) {

			curl_slist_free_all(headers);
			curl_easy_cleanup(curl);
			curl_global_cleanup();
		}
		fclose(fp);
		return true;
	}

	fclose(fp);
	return false;
}


bool postUrl(const char *filename) {
	CURL *curl;
	CURLcode res;
	FILE *fp;
	//if ((fp = fopen(filename, "w")) == NULL)
	//	return false;

	errno_t err = fopen_s(&fp, filename, "w");
	if (err != 0) {
		printf("open file error!\n");
		return false;
	}

	curl = curl_easy_init();
	if (curl) {
		curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookie.txt"); // 指定cookie文件
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86");    // 指定post内容
		curl_easy_setopt(curl, CURLOPT_URL, "www.baidu.com");   // 指定url
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
		res = curl_easy_perform(curl);
		curl_easy_cleanup(curl);
	}
	fclose(fp);
	return true;
}




int main(void) {
	getUrl("get.html");
	postUrl("post.html");


	system("pause");
	return 0;
}

二、案例

这里我就不讲解知识点了,网上我看到有其他博客写的很详细的了!

1. 使用回调函数将请求到的数据写入文件中

// 使用回调函数将请求到的数据写入文件中

#include 
#include 
#include "include/curl/curl.h"

using namespace std;

size_t ncWriteFile(void *buffer, size_t size, size_t nmemb, void *lpVoid) {
	FILE *stream = (FILE *)lpVoid;

	if (stream == NULL || buffer == NULL) {
		return -1;
	}
	size_t nWrite = fwrite(buffer, size, nmemb, stream);	// 写入文件

	return nWrite;
}

void SendGet() {
	FILE *fp;

	errno_t err = fopen_s(&fp, "1.txt", "w");
	if (err != 0) {
		cout << "文件打开失败!" << endl;
		return;
	}

	CURL *curl;
	CURLcode res;

	struct curl_slist * headers = NULL;
	headers = curl_slist_append(headers, "Content-Type:application/json");
	//std::string url = "192.168.74.1";
	std::string url = "www.baidu.com";
	
	curl = curl_easy_init();	// 初始化
	if (curl) {
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());			// 请求地址
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);		// 请求头
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ncWriteFile);	// 写入数据的回调函数
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)fp);		// 文件指针
		res = curl_easy_perform(curl);	// 执行

		if (res != 0) {
			curl_slist_free_all(headers);
			curl_easy_cleanup(curl);
		}
	}

	fclose(fp);
}


void SendPost() {
	CURL *curl;
	CURLcode res;

	struct curl_slist *headers = NULL;
	headers = curl_slist_append(headers, "Content-Type:application/json");
	//std::string url = "192.168.74.1";
	std::string url = "www.baidu.com";
	curl = curl_easy_init();		// 初始化
	if (curl) {
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());		// 请求地址
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);	// 请求头
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);		// 请求参数
		curl_easy_setopt(curl, CURLOPT_POST, 1);	// 设置非0表示本次操作位post请求
		res = curl_easy_perform(curl);		// 执行
		if (res != 0) {
			curl_slist_free_all(headers);
			curl_easy_cleanup(curl);
		}
	}
}


int main3(void) {
	SendGet();
	SendPost();

	return 0;
}

2. 上传文件到FTP

/* File FTP upload */


#include 
#include 
#include "include/curl/curl.h"

size_t read_data(void *buffer, size_t size, size_t nmemb, void *user_p) {
	return fread(buffer, size, nmemb, (FILE *)user_p);
}

BOOL filesUpload() {
	// 初始化libcurl
	CURLcode code;
	code = curl_global_init(CURL_GLOBAL_WIN32);
	if (code != CURLE_OK) {
		std::cout << "init libcurl failed." << std::endl;
		return FALSE;
	}

	FILE *fp = NULL;
	errno_t err = fopen_s(&fp, "text.html", "rb");
	if (err != 0) {
		std::cout << "open file text.html fail!" << std::endl;
		return FALSE;
	}

	// 获取文件大小
	int fileSize = ftell(fp);
	rewind(fp);	// 文件指针定位到开头

	// 获取easy handle
	CURL *easy_handle = NULL;
	easy_handle = curl_easy_init();
	if (easy_handle == NULL) {
		std::cout << "get a seay handle failed." << std::endl;
		fclose(fp);
		curl_global_cleanup();
		return FALSE;
	}

	// 设置eash handle 属性
	curl_easy_setopt(easy_handle, CURLOPT_URL, "ftp://***");
	curl_easy_setopt(easy_handle, CURLOPT_UPLOAD, 1L);		// 告诉libcurl,执行的是上传操作
	curl_easy_setopt(easy_handle, CURLOPT_READFUNCTION, &read_data);	// 设置回调函数
	curl_easy_setopt(easy_handle, CURLOPT_READDATA, &fp);	// 设置回调函数最后一个参数
	curl_easy_setopt(easy_handle, CURLOPT_INFILESIZE_LARGE, fileSize);	// 告诉libcurl要上传文件的大小
	
	// 执行上传操作
	code = curl_easy_perform(easy_handle);
	if (code != CURLE_OK) {
		std::cout << "upload file failed." << std::endl;
		return FALSE;
	}

	// 释放资源
	fclose(fp);
	curl_easy_cleanup(easy_handle);
	curl_global_cleanup();

	return TRUE;
}


int main4(void) {

	filesUpload();

	return 0;
}

3. curl_formadd - 表单文件上传和上传数据

/* curl_formadd表单文件上传和上传数据 */

#include 
#include "include/curl/curl.h"
#include 

using namespace std;

//回调函数  得到响应内容
int write_data(void* buffer, int size, int nmemb, void* userp) {
	std::string* str = dynamic_cast<std::string*>((std::string*)userp);
	str->append((char*)buffer, size * nmemb);
	return nmemb;
}
int upload(string url, string& body, string* response);

int main(int argc, char** argv) {

	std::string body;
	std::string response;

	int status_code = upload("192.168.74.1", body, &response);
	if (status_code != CURLcode::CURLE_OK) {
		return -1;
	}
	cout << body << endl;
	cout << response << endl;

	return 0;
}

int upload(string url, string& body, string* response) {
	CURL* curl;
	CURLcode ret;
	curl = curl_easy_init();
	struct curl_httppost* post = NULL;
	struct curl_httppost* last = NULL;
	

	if (curl) {
		curl_easy_setopt(curl, CURLOPT_URL, (char*)url.c_str());           //指定url

		// 表单上传
		curl_formadd(&post, &last, CURLFORM_PTRNAME, "name", CURLFORM_PTRCONTENTS, "ggggggg", CURLFORM_END);//form-data key(path) 和 value(device_cover)
		curl_formadd(&post, &last, CURLFORM_PTRNAME, "sex", CURLFORM_PTRCONTENTS, "1", CURLFORM_END);//form-data key(path) 和 value(device_cover)
		
		// 文件上传																	// 指定上传后的名字为1.pdf
		curl_formadd(&post, &last, CURLFORM_PTRNAME, "file", CURLFORM_FILE, "1.html", CURLFORM_FILENAME, "1.pdf", CURLFORM_END);

		curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);                     // 构造post参数  通过此操作将文件操作绑定上传 
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);          // 绑定相应
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)response);        // 绑定响应内容的地址

		ret = curl_easy_perform(curl);                          //执行请求
		if (ret == 0) {
			curl_easy_cleanup(curl);
			return 0;
		} else {
			return ret;
		}
	} else {
		return -1;
	}
}

4. 小插曲 - 验证是否上传成功

文件按和数据是上传了,但是我该怎么知道有没有上传成功呢?

因为我们有没有可以验证的服务器!

没关系,可以下载一个小工具进行验证,名字叫:NetAssist

下载后打开是这样的:
C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第11张图片
然后:
C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第12张图片

然后你再次运行程序:
C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第13张图片
可以看到设置的数据和文件数据都已经上传到TCP服务器了,这就证明上传成功了!

5. C++用libcurl通过HTTP以表单的方式Post数据到服务器


/* C++用libcurl通过HTTP以表单的方式Post数据到服务器 */

#if 0
// post字符串,将字符串上传
#include 
#include "include/curl/curl.h"

int main(void) {

	CURL *curl = NULL;
	CURLcode res;

	curl = curl_easy_init();	// 初始化
	if (curl == NULL) {
		return CURLE_FAILED_INIT;
	}

	struct curl_slist *headerlist = NULL;

	// 设置表头
	headerlist = curl_slist_append(headerlist, "Content-Type:application/x-www-form-urlencoded");
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);

	// 设置URL
	curl_easy_setopt(curl, CURLOPT_URL, "192.168.74.1");

	// 设置参数
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=guangzhou&project=tianhe");

	// 设置为Post
	curl_easy_setopt(curl, CURLOPT_POST, 1);

	// 执行
	res = curl_easy_perform(curl);
	if (res != CURLE_OK) {
		// 获取详细信息
		const char *szErr = curl_easy_strerror(res);
		fprintf(stderr, "curl_easy_perform() failed : %s\n", szErr);
	}

	// 清空
	curl_easy_cleanup(curl);

	// 释放表头
	curl_slist_free_all(headerlist);

	return 0;

}
#endif


#if 0
/* 表单上传数据和文件 */
#include 
#include 
#include "include/curl/curl.h"

size_t onWriteData(void *buffer, size_t size, size_t nmemb, void *lpVoid);

int main(void) {

	CURL *curl = NULL;
	CURLcode res;

	curl = curl_easy_init();
	if (curl == NULL) {
		return CURLE_FAILED_INIT;
	}

	struct curl_slist *headerlist = NULL;
	struct curl_httppost *formpost = NULL;
	struct curl_httppost *lastptr = NULL;
	std::string strResponse;	// 回复

	// 设置要上传的数据
	curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "ParamName1", CURLFORM_COPYCONTENTS, "ParamName1Content",  CURLFORM_END);
	curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "ParamName2", CURLFORM_COPYCONTENTS, "ParamName2Content", CURLFORM_END);
	curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "ParamName3", CURLFORM_COPYCONTENTS, "ParamName3Content", CURLFORM_END);
	// 设置要上传的文件
	curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "registerImage", CURLFORM_FILE, "Image.png", CURLFORM_CONTENTTYPE, "application/x-png", CURLFORM_END);
	curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "html", CURLFORM_FILE, "1.html", CURLFORM_END);
	curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "html", CURLFORM_FILE, "text.html", CURLFORM_END);
	curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "txt", CURLFORM_FILE, "text.txt", CURLFORM_END);
	/* curl_formadd(&post, &last, CURLFORM_COPYNAME, "file", CURLFORM_FILE, filepath, CURLFORM_CONTENTTYPE, "application/x-jpg", CURLFORM_END);     
	//application/x-jpg是jpg文件的类型,具体要根据自己上传的文件类型进行设置,参考http://tools.jb51.net/table/http_content_type */

	// 设置表头
	headerlist = curl_slist_append(headerlist, "Content-Type:application/urlencoded");
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);

	// 设置URL
	curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.74.1");

	// 现在指定POST数据
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=guangzhou&project=panyu");
	// 设置位post
	curl_easy_setopt(curl, CURLOPT_POST, 1);

	curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);                     //构造post参数
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	//curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	//curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);

	// 执行
	res = curl_easy_perform(curl);
	if (res != CURLE_OK) {
		// 获取详细错误信息
		const char *szErr = curl_easy_strerror(res);
		fprintf(stderr, "curl_easy_perform() failed : %s\n", szErr);
	}

	// 清空
	curl_easy_cleanup(curl);

	// 释放表单
	curl_formfree(formpost);

	// 释放表头
	curl_slist_free_all(headerlist);

	return 0;
}


size_t onWriteData(void *buffer, size_t size, size_t nmemb, void *lpVoid) {
	std::string *str = dynamic_cast<std::string *>((std::string *)lpVoid);
	if (str == NULL || buffer == NULL) {
		return -1;
	}

	char *pData = (char *)buffer;
	str->append(pData, size * nmemb);

	return nmemb;
}

#endif

6. 使用回调函数文件上传

/* 使用回调函数文件上传 */

#include 
#include "include/curl/curl.h"
#include 
#include 


size_t readData(void *buffer, size_t size, size_t nmemb, void *user_p) {
	return fread(buffer, size, nmemb, (FILE *)user_p);
}

int main7(void) {

	CURL *curl;
	CURLcode res;
	struct stat file_info;
	curl_off_t speed_upload, total_time;
	FILE *fd;

	errno_t err = fopen_s(&fd, "text.txt", "rb");
	if (err != 0) {
		printf("open file 1.html fail!\n");
		return -1;
	}

	if (fstat(_fileno(fd), &file_info) != 0) {
		return -1;
	}

	curl = curl_easy_init();
	if (curl) {
		// 上传到这个位置
		curl_easy_setopt(curl, CURLOPT_URL, "192.168.74.1");
		// 告诉他上传到URL
		curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
		// 告诉他从Windows上读取文件上传
		curl_easy_setopt(curl, CURLOPT_READDATA, fd);
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, readData);
		// 并给出上传的大小
		curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
		// 启用详细信息以更容易跟踪
		//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		res = curl_easy_perform(curl);
		if (res != CURLE_OK) {
			// 打印错误信息
			fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
		
		} else {
			// 提取信息
			curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD_T, &speed_upload);
			curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME_T, &total_time);

			fprintf(stderr, "Speed: %" CURL_FORMAT_CURL_OFF_T " bytes/sec during %"
				CURL_FORMAT_CURL_OFF_T ".%06ld seconds\n",
				speed_upload,
				(total_time / 1000000), (long)(total_time % 1000000));
		}

		// 释放
		curl_easy_cleanup(curl);
	}

	fclose(fd);

	return 0;
}

7. 通过回调函数上传数据


/* 通过回调函数上传数据 */


#include 
#include 
#include "include/curl/curl.h"


#define USE_CHUNKED 1

/* silly test data to POST */
static const char data[] = "Lorem ipsum dolor sit amet, consectetur adipiscing "
"elit. Sed vel urna neque. Ut quis leo metus. Quisque eleifend, ex at "
"laoreet rhoncus, odio ipsum semper metus, at tempus ante urna in mauris. "
"Suspendisse ornare tempor venenatis. Ut dui neque, pellentesque a varius "
"eget, mattis vitae ligula. Fusce ut pharetra est. Ut ullamcorper mi ac "
"sollicitudin semper. Praesent sit amet tellus varius, posuere nulla non, "
"rhoncus ipsum.";

struct WriteThis {
	const char *readptr;
	size_t sizeleft;
};

static size_t read_callback(char *dest, size_t size, size_t nmemb, void *userp) {
	struct WriteThis *wt = (struct WriteThis *)userp;
	size_t buffer_size = size * nmemb;

	if (wt->sizeleft) {
		/* copy as much as possible from the source to the destination */
		size_t copy_this_much = wt->sizeleft;
		if (copy_this_much > buffer_size)
			copy_this_much = buffer_size;
		memcpy(dest, wt->readptr, copy_this_much);

		wt->readptr += copy_this_much;
		wt->sizeleft -= copy_this_much;
		return copy_this_much; /* we copied this many bytes */
	}

	return 0; /* no more data left to deliver */
}

int main8(void) {
	CURL *curl;
	CURLcode res;

	struct WriteThis wt;

	wt.readptr = data;
	wt.sizeleft = strlen(data);

	/* In windows, this will init the winsock stuff */
	res = curl_global_init(CURL_GLOBAL_DEFAULT);
	/* Check for errors */
	if (res != CURLE_OK) {
		fprintf(stderr, "curl_global_init() failed: %s\n",
			curl_easy_strerror(res));
		return 1;
	}

	/* get a curl handle */
	curl = curl_easy_init();
	if (curl) {
		/* First set the URL that is about to receive our POST. */
		curl_easy_setopt(curl, CURLOPT_URL, "192.168.74.1");

		/* Now specify we want to POST data */
		curl_easy_setopt(curl, CURLOPT_POST, 1L);

		/* we want to use our own read function */
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);

		/* pointer to pass to our read function */
		curl_easy_setopt(curl, CURLOPT_READDATA, &wt);

		/* get verbose debug output please */
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		/*
		  If you use POST to a HTTP 1.1 server, you can send data without knowing
		  the size before starting the POST if you use chunked encoding. You
		  enable this by adding a header like "Transfer-Encoding: chunked" with
		  CURLOPT_HTTPHEADER. With HTTP 1.0 or without chunked transfer, you must
		  specify the size in the request.
		*/
#ifdef USE_CHUNKED
		{
			struct curl_slist *chunk = NULL;

			chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked");
			res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
			/* use curl_slist_free_all() after the *perform() call to free this
			   list again */
		}
#else
		/* Set the expected POST size. If you want to POST large amounts of data,
		   consider CURLOPT_POSTFIELDSIZE_LARGE */
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)wt.sizeleft);
#endif

#ifdef DISABLE_EXPECT
		/*
		  Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue"
		  header.  You can disable this header with CURLOPT_HTTPHEADER as usual.
		  NOTE: if you want chunked transfer too, you need to combine these two
		  since you can only set one list of headers with CURLOPT_HTTPHEADER. */

		  /* A less good option would be to enforce HTTP 1.0, but that might also
			 have other implications. */
		{
			struct curl_slist *chunk = NULL;

			chunk = curl_slist_append(chunk, "Expect:");
			res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
			/* use curl_slist_free_all() after the *perform() call to free this
			   list again */
		}
#endif

		/* Perform the request, res will get the return code */
		res = curl_easy_perform(curl);
		/* Check for errors */
		if (res != CURLE_OK)
			fprintf(stderr, "curl_easy_perform() failed: %s\n",
				curl_easy_strerror(res));

		/* always cleanup */
		curl_easy_cleanup(curl);
	}
	curl_global_cleanup();
	return 0;
}

8. curl_formadd - 表单上传多个文件

/* curl_formadd - 表单上传多个文件 */

#include 
#include 
#include 
#include "include/curl/curl.h"


#define PERM 0

int main9(void) {
	CURL *curl;
	CURLcode rcode;
	const char *url = "192.168.74.1";
	const char *head_t = "66666666";
	char heads[1024];
	struct curl_httppost *formpost = NULL;
	struct curl_httppost *lastptr = NULL;
	struct curl_slist *headers = NULL; /* init to NULL is important */
	sprintf_s(heads, "head-sky:%s", head_t);

	headers = curl_slist_append(headers, heads);

	rcode = curl_global_init(CURL_GLOBAL_ALL);
	if (CURLE_OK != rcode)
		return 0;

	curl = curl_easy_init();
	if (NULL == curl)
		curl_global_cleanup();

#if PERM == 1
	/*设置发送单个文件*/
	curl_formadd(&formpost,
		&lastptr,
		CURLFORM_COPYNAME, "sendfile",
		CURLFORM_FILE, name,
		CURLFORM_END);
#else
	/*设置发送多个文件*/	// 方式一
	struct curl_forms array[3];
	array[0].option = CURLFORM_FILE;
	array[0].value = "1.html";
	array[1].option = CURLFORM_FILE;
	array[1].value = "text.jpg";
	array[2].option = CURLFORM_END;
	curl_formadd(&formpost,
		&lastptr,
		CURLFORM_COPYNAME, "sendfile",
		CURLFORM_ARRAY, array,
		CURLFORM_END);
#endif

	// 或者下面这种方式上传多个文件		// 方式二
	curl_formadd(&formpost,
		&lastptr,
		CURLFORM_COPYNAME, "filename",
		CURLFORM_COPYCONTENTS, "1.html",
		CURLFORM_END);

	curl_formadd(&formpost,
		&lastptr,
		CURLFORM_COPYNAME, "filename",
		CURLFORM_COPYCONTENTS, "text.jpg",
		CURLFORM_END);


	curl_formadd(&formpost,
		&lastptr,
		CURLFORM_COPYNAME, "submit",
		CURLFORM_COPYCONTENTS, "send",
		CURLFORM_END);

	/

	//设置发送http头部
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
	//设置url
	curl_easy_setopt(curl, CURLOPT_URL, url);
	//设置http以post方式请求
	curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
	//设置超时时间
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);

	//发送数据
	rcode = curl_easy_perform(curl);
	if (rcode != CURLE_OK) {
		fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(rcode));
	}

	curl_formfree(formpost);
	curl_easy_cleanup(curl);
	curl_slist_free_all(headers);
	curl_global_cleanup();
	return 0;
}

9. curl_mime_data - 表单上传多个文件

/* curl_mime_data - 表单上传多个文件 */

#include 
#include 
#include "include/curl/curl.h"

int main10(void) {
	CURL *curl;
	CURLcode res;

	curl_mime *form = NULL;
	curl_mimepart *field = NULL;
	struct curl_slist *headerlist = NULL;
	static const char buf[] = "Expect:";


	curl_global_init(CURL_GLOBAL_ALL);

	curl = curl_easy_init();
	if (curl == NULL) {
		printf("curl_easy_init() init fail!\n");
		curl_global_cleanup();
	}

	// 创建表单
	form = curl_mime_init(curl);

	// 填写文件上传字段
	field = curl_mime_addpart(form);
	curl_mime_name(field, "sendfile");
	curl_mime_filedata(field, "1.html");

	// 填写文件名字段
	field = curl_mime_addpart(form);
	curl_mime_name(field, "filename");
	curl_mime_data(field, "1.html", CURL_ZERO_TERMINATED);


	// 填写文件上传字段
	field = curl_mime_addpart(form);
	curl_mime_name(field, "sendfile");
	curl_mime_filedata(field, "text.html");

	// 填写文件名字段
	field = curl_mime_addpart(form);
	curl_mime_name(field, "filename");
	curl_mime_data(field, "text.html", CURL_ZERO_TERMINATED);



	// 填写提交字段
	field = curl_mime_addpart(form);
	curl_mime_name(field, "submit");
	curl_mime_data(field, "send", CURL_ZERO_TERMINATED);

	// 请求头
	headerlist = curl_slist_append(headerlist, buf);
	// URL
	curl_easy_setopt(curl, CURLOPT_URL, "192.168.74.1");

	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
	curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);

	// 执行
	res = curl_easy_perform(curl);
	if (res != CURLE_OK) {
		fprintf(stderr, "curl_easy_perform() failed: %s \n", curl_easy_strerror(res));
	}

	curl_easy_cleanup(curl);
	curl_mime_free(form);
	curl_slist_free_all(headerlist);

	return 0;
}

10. 使用多线程上传多个文件

/* 使用多线程上传多个文件 */

#include 
#include "include/curl/curl.h"
#include 
#include 
#include 
#include 


#define UPLOAD_THREAD_COUNT 3


typedef struct U_FN {
	char *urlArr;
	char *filePathArr;
}UFN;

size_t readData2(void *buffer, size_t size, size_t nmemb, void *user_p) {
	return fread(buffer, size, nmemb, (FILE *)user_p);
}


unsigned int WINAPI uploadFile(void *_ufn) {
	UFN *ufn = (UFN *)_ufn;
	CURL *curl;
	CURLcode res;
	struct stat file_info;
	curl_off_t speed_upload, total_time;
	FILE *fd;

	//Sleep(100);
	errno_t err = fopen_s(&fd, ufn->filePathArr, "rb");
	if (err != 0) {
		printf("open file %s fail!\n", ufn->filePathArr);
		return -1;
	}

	if (fstat(_fileno(fd), &file_info) != 0) {
		return -1;
	}

	curl = curl_easy_init();
	if (curl) {
		// 上传到这个位置
		curl_easy_setopt(curl, CURLOPT_URL, ufn->urlArr);
		// 告诉他上传到URL
		curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
		// 告诉他从Windows上读取文件上传
		curl_easy_setopt(curl, CURLOPT_READDATA, fd);
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, readData2);
		// 并给出上传的大小
		curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
		// 启用详细信息以更容易跟踪
		//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		res = curl_easy_perform(curl);
		if (res != CURLE_OK) {
			// 打印错误信息
			fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));

		} else {
			// 提取信息
			curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD_T, &speed_upload);
			curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME_T, &total_time);

			fprintf(stderr, "Speed: %" CURL_FORMAT_CURL_OFF_T " bytes/sec during %"
				CURL_FORMAT_CURL_OFF_T ".%06ld seconds\n",
				speed_upload,
				(total_time / 1000000), (long)(total_time % 1000000));
		}

		// 释放
		curl_easy_cleanup(curl);
	}

	fclose(fd);

	return 0;
}




int main13(void) {

	UFN ufn[UPLOAD_THREAD_COUNT];

	ufn[0].filePathArr = (char *)"1.html";
	ufn[0].urlArr = (char *)"192.168.74.1";
	ufn[1].filePathArr = (char *)"text.jpg";
	ufn[1].urlArr = (char *)"192.168.74.1";
	ufn[2].filePathArr = (char *)"text.txt";
	ufn[2].urlArr = (char *)"192.168.74.1";

	HANDLE tHandles[UPLOAD_THREAD_COUNT];

	for (int i = 0; i < UPLOAD_THREAD_COUNT; i++) {
		// 至少需要加上20毫秒的延时,否则会连接失败!
		Sleep(20);
		tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, uploadFile, (void *)&ufn[i], 0, NULL);
	}

	// 阻塞多个线程句柄,直到子线程运行完毕,主线程才会往下走
	WaitForMultipleObjects(UPLOAD_THREAD_COUNT, tHandles, TRUE, INFINITE);
	printf("%d个文件已经上传完成!\n", UPLOAD_THREAD_COUNT);

	return 0;
}

11. 请求下载文件

可以通过CURLOPT_PROGRESSFUNCTION设置下载进度显示

/* 请求下载文件 */

#include 
#include 
#include 

#include "./include/curl/curl.h"
#include "./include/curl/easy.h"


using namespace std;

// 这个函数是为了符合CURLOPT_WRITEFUNCTION而构造的
// 完成数据保存功能
size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) {
	// 从ptr中读取数据写入文件流中
	int written = fwrite(ptr, size, nmemb, (FILE *)stream);

	return written;
}

// 这个函数是为了符合CURLOPT_PROGRESSFUNCTION而构造的
// 完成数据保存功能
int my_progress_func(char *progress_data, double dltotal, double dlnow, double ultotal, double ulnow) {

	printf("%s 已下载:%.2f MB\n", progress_data, dlnow / (1024 * 1024));
	Sleep(100);
	return 0;
}


int main2(void) {

	CURL *curl;
	CURLcode res;
	const char *progress_data = "* ";

	// 定义FILE类型指针
	FILE *fp = NULL;

	res = curl_global_init(CURL_GLOBAL_ALL);
	if (res != CURLE_OK) {
		printf("curl_global_init(CURL_GLOBAL_ALL) is fail!\n");
		exit(-1);
	}

	curl = curl_easy_init();
	if (curl) {
		
		errno_t err = fopen_s(&fp, "text.txt", "wb");
		if (err != 0) {
			printf("open file fail!\n");
			exit(-1);
		}


		//curl_easy_setopt(curl, CURLOPT_URL, "192.168.74.1");	// 设置url链接
		curl_easy_setopt(curl, CURLOPT_URL, "http://www.newbiquge.com/modules/article/txtarticle.php?id=4486");	// 设置url链接
		// CURLOPT_WRITEFUNCTION 将后续的动作交给write_data函数处理
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);

		// 显示下载进度
		curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
		curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, my_progress_func);
		curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, progress_data);

		// 不接收响应头数据0代表不接收 1代表接收
		curl_easy_setopt(curl, CURLOPT_HEADER, 0);


		res = curl_easy_perform(curl);	// 执行
		if (res != CURLE_OK) {
			printf("curl_easy_perform(curl) is fail!\n");
			curl_easy_cleanup(curl);	// 释放
			exit(-1);
		}
		curl_easy_cleanup(curl);	// 释放
	}


	curl_global_cleanup();
	fclose(fp);
	
	return 0;
}

下载你可以使用一些网络监测工具查看是否有下载操作,例如我这里使用360加速球看的。
C++ vs2017 - libcurl - http请求 代码大全(请求数据,上传下载文件,多线程上传下载文件)_第14张图片

12. 同时下载多个文件 - 无法实现保存到本地,只能实现下载效果

/* 同时下载多个文件 - 无法实现保存到本地,只能实现下载效果 */

#include 
#include 
#include 
#include "include/curl/curl.h"


// 这些是下载的url
static const char *urls[] = {
  "http://www.newbiquge.com/modules/article/txtarticle.php?id=4486",
  "http://bpic.588ku.com/element_origin_min_pic/16/10/29/2ac8e99273bc079e40a8dc079ca11b1f.jpg"
};

#define MAX_PARALLEL 2
#define NUM_URLS sizeof(urls) / sizeof(char *)

static size_t write_cb(char *data, size_t n, size_t l, void *userp) {
	// 忽略...
	(void)data;
	(void)userp;

	return n * l;
}


static void add_transfer(CURLM *cm, int i) {
	CURL *eh = curl_easy_init();

	curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, write_cb);
	curl_easy_setopt(eh, CURLOPT_URL, urls[i]);

	// 在这把调用的网址存下,后面curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url);查询出来
	curl_easy_setopt(eh, CURLOPT_PRIVATE, urls[i]);	

	curl_multi_add_handle(cm, eh);
}



int main11(void) {
	CURLM *cm;
	CURLMsg *msg;
	unsigned int transfers = 0;
	int msgs_left = -1;
	int still_alive = 1;

	curl_global_init(CURL_GLOBAL_ALL);
	cm = curl_multi_init();

	// 限制同时连接的数量卷曲应该允许:
	curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)MAX_PARALLEL);

	for (transfers = 0; transfers < MAX_PARALLEL; transfers++) {
		add_transfer(cm, transfers);
	}
	

	do {
		// 执行
		curl_multi_perform(cm, &still_alive);

		while ((msg = curl_multi_info_read(cm, &msgs_left))) {
			if (msg->msg == CURLMSG_DONE) {
				char *url;
				CURL *e = msg->easy_handle;
				curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url);
				fprintf(stderr, "R:%d - %s <%s>\n", msg->data.result, curl_easy_strerror(msg->data.result), url);

				curl_multi_remove_handle(cm, e);
				curl_easy_cleanup(e);
			
			} else {
				fprintf(stderr, "E:CURLMsg (%d) \n", msg->msg);
			}

			// 如果还有链接,继续添加,继续下载
			if (transfers < NUM_URLS) {
				add_transfer(cm, transfers++);
			}
		}

		if (still_alive) {
			curl_multi_wait(cm, NULL, 0, 1000, NULL);
		}
	
	} while (still_alive || (transfers < NUM_URLS));

	curl_multi_cleanup(cm);
	curl_global_cleanup();

	return EXIT_SUCCESS;
}

13. 使用多线程请求下载多个文件

/* 使用多线程请求下载多个文件 */

#include 
#include 
#include 
#include 

#include "./include/curl/curl.h"
#include "./include/curl/easy.h"


using namespace std;


#define THREAD_COUNT 2

typedef struct URL_FN {
	char *urlArr;
	char *filePathArr;
}UF;


// 这个函数是为了符合CURLOPT_WRITEFUNCTION而构造的
// 完成数据保存功能
size_t write_data2(void *ptr, size_t size, size_t nmemb, void *stream) {
	// 从ptr中读取数据写入文件流中
	int written = fwrite(ptr, size, nmemb, (FILE *)stream);

	return written;
}

// 这个函数是为了符合CURLOPT_PROGRESSFUNCTION而构造的
// 完成数据保存功能
int my_progress_func2(char *progress_data, double dltotal, double dlnow, double ultotal, double ulnow) {

	printf("%s 已下载:%.2f MB\n", progress_data, dlnow / (1024 * 1024));

	return 0;
}


unsigned int WINAPI downloadFile(void *_uf) {
	UF *uf = (UF *)_uf;
	CURL *curl;
	CURLcode res;
	const char *progress_data = "* ";

	// 定义FILE类型指针
	FILE *fp = NULL;

	res = curl_global_init(CURL_GLOBAL_ALL);
	if (res != CURLE_OK) {
		printf("curl_global_init(CURL_GLOBAL_ALL) is fail!\n");
		return 0;
	}

	curl = curl_easy_init();
	if (curl) {

		errno_t err = fopen_s(&fp, uf->filePathArr, "wb");
		if (err != 0) {
			printf("open file %s fail!\n", uf->filePathArr);
			return 0;
		}


		//curl_easy_setopt(curl, CURLOPT_URL, "192.168.74.1");	// 设置url链接
		curl_easy_setopt(curl, CURLOPT_URL, uf->urlArr);	// 设置url链接
		// CURLOPT_WRITEFUNCTION 将后续的动作交给write_data函数处理
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data2);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);

		// 显示下载进度
		curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
		curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, my_progress_func2);
		curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, progress_data);

		//不接收响应头数据0代表不接收 1代表接收
		curl_easy_setopt(curl, CURLOPT_HEADER, 0);


		curl_easy_perform(curl);	// 执行
		curl_easy_cleanup(curl);	// 释放
	}


	curl_global_cleanup();
	fclose(fp);

	return 0;
}


int main12(void) {

	UF uf[THREAD_COUNT];

	// 设置下载的url和下载后保存的路径和文件名
	uf[0].urlArr =		(char *)"http://www.newbiquge.com/modules/article/txtarticle.php?id=4486";
	uf[0].filePathArr = (char *)"C:\\Users\\gzsa\\Desktop\\abc.txt";
	uf[1].urlArr =		(char *)"http://bpic.588ku.com/element_origin_min_pic/16/10/29/2ac8e99273bc079e40a8dc079ca11b1f.jpg";
	uf[1].filePathArr = (char *)"C:\\Users\\gzsa\\Desktop\\abc.jpg";


	HANDLE tHandles[THREAD_COUNT];

	for (int i = 0; i < THREAD_COUNT; i++) {
		tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, downloadFile, (void *)&uf[i], 0, NULL);
	}
	
	//for (int j = 0; j < 10000; j++) {
	//	printf("%d\n", j);
	//}

	// 阻塞多个线程句柄,直到子线程运行完毕,主线程才会往下走
	WaitForMultipleObjects(THREAD_COUNT, tHandles, TRUE, INFINITE);
	printf("%d个文件已经下载完成!\n", THREAD_COUNT);
	

	return 0;
}

三、总结

官方案例:https://curl.se/libcurl/c/example.html

这些案例都是在网上扒的和官网的案例,还有一些是自己写的,我只是将一些我觉得比较实用的例子记录下来!

你可能感兴趣的:(c++,c++,http,libcurl)