259次浏览

分享一份C/C++ libcurl库 支持ssl+使用例子

libcurl是一个免费开源的客户端url传输库,支持多种协议, 已经被很多知名的大企业所采用。

官方项目github地址: https://github.com/curl/curl

我的编译环境:vs2015,库版本:curl-7.70.0+openssl-1.1.1g

已编译库下载地址: https://66-1251737204.cos.ap-beijing-1.myqcloud.com/citext.cn/Library/openssl_curl.rar

下面代码简单封装了下GET请求和POST请求, 支持ssl网页

当然, 代码还有非常大的改进空间, 你也可以封装成类

测试线程数为20, 长时间运行并没有发生内存泄漏。

libcurl test

main.cpp

int main()
{
        curl_global_init(CURL_GLOBAL_ALL);
	char ret_header[5024];
	char ret_cookies[5024];
	char content[40 * 1000];
	char header[5024] = "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36\r\nContent-Type: application/x-www-form-urlencoded";
	int ret_header_size = NULL;
	int content_size = NULL;


	//POST登录网站, 禁止重定向否则取不到cookies
	PostUrlHTTP("http://www.hoolay.cn/login?url=", "uid=00000485@qq.com&password=123456789",
		content, 10, header, nullptr, ret_header, &ret_header_size, &content_size, ret_cookies, 0);

	std::cout << ret_cookies << std::endl;



	//登录成功我们就带上成功cookies去访问用户管理页面
	memset(header, 0, sizeof(header));
	strcat(header, "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36\r\nCookie: ");
	strcat(header, ret_cookies);


	GetUrlHTTP("http://www.hoolay.cn/mypanel/orders", content, 10, header, nullptr,
		ret_header, &ret_header_size, &content_size, ret_cookies, 0);

	std::cout <<UTF8ToGBK(content) << std::endl;
	std::cout << ret_cookies << std::endl;
     curl_global_cleanup();
     return 0;
}

http.h

#pragma once
#include<curl\curl.h>
#include<stdio.h>
#include<iostream>
#include<fstream>
#include<thread>
#include <vector>
#include<mutex>
#include<string>
#include <regex>


struct MemoryStruct {
	std::vector<char>memory;
	size_t size;
};


int GetUrlHTTP(char *url, char *ret_response, int time_out, char *header, char *proxy,
	char* ret_header, int *ret_header_size, int *ret_content_size, char *ret_cookies, bool Redirect);

int PostUrlHTTP(char *url, char* PostData, char *ret_response, int time_out, char *header, char *proxy,
	char* ret_header, int *ret_header_size, int *ret_content_size, char *ret_cookies, bool Redirect);

std::string GBKToUTF8(const std::string& strGBK);
std::string UTF8ToGBK(char* strUTF8);

http.cpp

#include"http.h"

//网页响应内容回调
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
	size_t realsize = size * nmemb;
	struct MemoryStruct *mem = (struct MemoryStruct *)userp;
	mem->memory.reserve(realsize);
	for (size_t i = 0; i < realsize; i++)
	{
		mem->memory.push_back(((char *)contents)[i]);
	}

	mem->size += realsize;
	return realsize;
}

//网页响应协议头回调
static size_t HeaderCallback(void *contents, size_t size, size_t nmemb, void *userp)
{

	size_t realsize = size * nmemb;
	struct MemoryStruct *mem = (struct MemoryStruct *)userp;
	mem->memory.reserve(realsize);
	for (size_t i = 0; i < realsize; i++)
	{
		mem->memory.push_back(((char *)contents)[i]);
	}

	mem->size += realsize;
	return realsize;
}

int PostUrlHTTP(char *url,char* PostData, char *ret_response, int time_out, char *header, char *proxy,
	char* ret_header, int *ret_header_size, int *ret_content_size,char *ret_cookies, bool Redirect)
{
	CURL *curl;
	CURLcode res;

	curl = curl_easy_init();

	if (curl)
	{
		MemoryStruct buffer, rheader;
		buffer.size = 0;
		rheader.size = 0;


		//curl_easy_setopt(curl, CURLOPT_HEADER, 1);//设为1,则在返回的内容里包含http header;

		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, (int)Redirect);//跟踪重定向
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, time_out);    /*timeout 30s,add by edgeyang*/
		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);    /*no signal,add by edgeyang*/

		curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");    //初始化cookie引擎,才能正确接收到cookie数据.
														   //curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookie_open.txt");

		curl_easy_setopt(curl, CURLOPT_PROXY, proxy);//设置代理
		curl_easy_setopt(curl, CURLOPT_URL, url);//设置链接
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
		curl_easy_setopt(curl, CURLOPT_HEADERDATA, &rheader);
		curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, PostData); //POST方式访问并且指定数据

		//忽略ssl验证
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

		curl_slist *headers = NULL;//创建协议头列表
		if (header)
		{
			//分割出协议头进行添加
			std::string token;
			std::string _header = header;
			int ind = 0;
			int ind1 = 0;

			while (true)
			{
				ind = _header.find("\r\n", ind);
				token = _header.substr(ind1, ind - ind1);

				headers = curl_slist_append(headers, token.c_str());

				if (ind != -1) {
					ind += 2;
					ind1 = ind;
				}
				else break;
			}
		}

		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

		res = curl_easy_perform(curl);//执行请求
		if (headers)
		{
			curl_slist_free_all(headers);
		}


		//std::cout << rheader.memory << std::endl;
		//std::cout << buffer.memory << std::endl;

		//数据末尾加上/0
		rheader.memory.push_back('\0');
		buffer.memory.push_back('\0');

		//返回响应内容
		if (ret_response)
		{
			memset(ret_response, 0, sizeof(ret_response));
			std::copy(buffer.memory.begin(), buffer.memory.end(), ret_response);
		}

		//返回协议头
		if (ret_header)
		{
			memset(ret_header, 0, sizeof(ret_header));
			std::copy(rheader.memory.begin(), rheader.memory.end(), ret_header);
		}

		//返回cookies
		if (ret_cookies)
		{
			memset(ret_cookies, 0, sizeof(ret_cookies));
			std::string text = &(rheader.memory[0]);;
			std::string cookies;

			//std::cout << text.c_str() << std::endl;

			//std::regex_token_iterator: 用于多次匹配正则表达式, 它可以获取整个正则表达式
			//的结果, 也可以获取正则表达式的前缀, 还可以获取正则表达式的分组子匹配

			//构造正则表达式
			//这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
			std::regex express("Set-Cookie:(.*?);");


			//(多次匹配)显示正则表达式子匹配, 1 表示第一组子匹配
			std::regex_token_iterator<std::string::const_iterator> begin2_3(text.cbegin(), text.cend(), express, 1);
			for (auto iter = begin2_3; iter != std::sregex_token_iterator(); iter++)
			{
				//std::cout << iter->length() << ": " << iter->str() << std::endl;
				cookies += iter->str();
				cookies += ";";

			}
			strcpy(ret_cookies, (char *)cookies.c_str());
		}

		//返回协议头大小
		if (ret_header_size)
		{
			*ret_header_size = rheader.size;
		}

		//返回响应大小
		if (ret_content_size)
		{
			*ret_content_size = buffer.size;
		}

		curl_easy_cleanup(curl);

	}

	return res;

}

int GetUrlHTTP(char *url, char *ret_response,int time_out, char *header,char *proxy,
	char* ret_header, int *ret_header_size, int *ret_content_size, char *ret_cookies,bool Redirect)
{
	CURL *curl;
	CURLcode res;

	curl = curl_easy_init();

	if (curl)
	{
		MemoryStruct buffer,rheader;
		buffer.size = 0;
		rheader.size = 0;
		
		//curl_easy_setopt(curl, CURLOPT_HEADER, 1);//设为1,则在返回的内容里包含http header;
		
		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, (int)Redirect);//跟踪重定向
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, time_out);    /*timeout 30s,add by edgeyang*/
		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);    /*no signal,add by edgeyang*/

		curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");    //初始化cookie引擎,才能正确接收到cookie数据.
		//curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookie_open.txt");

		curl_easy_setopt(curl, CURLOPT_PROXY, proxy);//设置代理
		curl_easy_setopt(curl, CURLOPT_URL, url);//设置链接
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
		curl_easy_setopt(curl, CURLOPT_HEADERDATA, &rheader);
		curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback);

		//忽略 ssl验证
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

		curl_slist *headers = NULL;//创建协议头列表
		if (header)
		{
			//分割出协议头进行添加
			std::string token;
			std::string _header = header;
			int ind = 0;
			int ind1 = 0;

			while (true)
			{
				ind = _header.find("\r\n", ind);
				token = _header.substr(ind1, ind - ind1);

				headers = curl_slist_append(headers, token.c_str());

				if (ind != -1) {
					ind += 2;
					ind1 = ind;
				}
				else break;
			}

		}

		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
		res = curl_easy_perform(curl);//执行请求
		if (headers)
		{
			curl_slist_free_all(headers);
		}

		//std::cout << rheader.memory << std::endl;
		//std::cout << buffer.memory << std::endl;

		//数据末尾加上/0
		rheader.memory.push_back('\0');
		buffer.memory.push_back('\0');

		//返回响应内容
		if (ret_response)
		{
			memset(ret_response, 0, sizeof(ret_response));
			std::copy(buffer.memory.begin(), buffer.memory.end(), ret_response);
		}

		//返回协议头
		if (ret_header)
		{
			memset(ret_header, 0, sizeof(ret_header));
			std::copy(rheader.memory.begin(), rheader.memory.end(), ret_header);
		}

		//返回cookies
		if (ret_cookies)
		{
			memset(ret_cookies, 0, sizeof(ret_cookies));
			std::string text = &(rheader.memory[0]);;
			std::string cookies;

			//std::cout << text.c_str() << std::endl;

			//std::regex_token_iterator: 用于多次匹配正则表达式, 它可以获取整个正则表达式
			//的结果, 也可以获取正则表达式的前缀, 还可以获取正则表达式的分组子匹配

			//构造正则表达式
			//这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
			std::regex express("Set-Cookie:(.*?);");


			//(多次匹配)显示正则表达式子匹配, 1 表示第一组子匹配
			std::regex_token_iterator<std::string::const_iterator> begin2_3(text.cbegin(), text.cend(), express, 1);
			for (auto iter = begin2_3; iter != std::sregex_token_iterator(); iter++)
			{
				//std::cout << iter->length() << ": " << iter->str() << std::endl;
				cookies += iter->str();
				cookies += ";";

			}
			strcpy(ret_cookies, (char *)cookies.c_str());
		}

		//返回协议头大小
		if (ret_header_size)
		{
			*ret_header_size = rheader.size;
		}

		//返回响应大小
		if (ret_content_size)
		{
			*ret_content_size = buffer.size;
		}

		curl_easy_cleanup(curl);

	}

		return res;
	}

std::string UTF8ToGBK(char* strUTF8)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, NULL, 0);
	WCHAR* wszGBK = new WCHAR[len + 1];
	memset(wszGBK, 0, len * 2 + 2);
	MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, wszGBK, len);

	len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
	char *szGBK = new char[len + 1];
	memset(szGBK, 0, len + 1);
	WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
	std::string strTemp(szGBK);
	delete[]szGBK;
	delete[]wszGBK;
	return strTemp;
}

std::string GBKToUTF8(const std::string& strGBK)
{
	std::string strOutUTF8 = "";
	WCHAR * str1;
	int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0);
	str1 = new WCHAR[n];
	MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n);
	n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);
	char * str2 = new char[n];
	WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL);
	strOutUTF8 = str2;
	delete[]str1;
	str1 = NULL;
	delete[]str2;
	str2 = NULL;
	return strOutUTF8;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注