libcurl 的基础使用

oneNeko 于 2020-08-17 发布

在工作中需要调用webservice服务,之前使用的是gsoap,但是编译比较麻烦,考虑到使用的webservice比较简单,只需要发送简单get请求即可获取数据,所以这里考虑使用libcurl库。

编译

下载

下载curl源代码:https://curl.haxx.se/download.html,选择一个版本下载,如curl-7.70.0 解压到指定目录,查看winbuild,里面有官方文档BUILD.WINDOWS.txt,文档里提示,要将依赖放在与curl目录同级的deps目录里面,如下

|_ curl-src  
| |_ winbuild  
|  
|_ deps  
  |_ lib  
  |_ include  
  |_ bin

构建

打开vs2015 本地命令行vs2015 x86 本机工具命令提示符 ,进入winbuild目录,然后执行

$ nmake /f Makefile.vc mode=dll VC=15 WITH_SSL=static ENABLE_SSPI=no ENABLE_IPV6=no

构建完成之后,会在根目录/builds/libcurl-vc15-x86-release-dll-ssl-static 找到生成的库。进入bin,使用普通cmd,执行

$ curl -V
# curl 7.70.0 (i386-pc-win32) libcurl/7.70.0 OpenSSL/1.1.1g WinIDN
# Release-Date: 2020-04-29
# Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
# Features: AsynchDNS HTTPS-proxy IDN Largefile NTLM SSL UnixSockets

带有OpenSSL则编译成功

引入

新建vs工程,在工程目录里新建includelib文件夹,将libcurl-vc15-x86-release-dll-ssl-static里的文件放入对应文件夹,curl\放入include\libcurl.lib放入lib\,把bin\下的libcurl.dll放在exe根目录(如果是https,还需要将ssl相关的dll放入,否则会报错)
然后再工程属性中添加对include和lib的引用

使用

这里主要是介绍基础使用,所以使用的是easy API

初始化

CURL *curl_easy_init( );
curl_easy_init用来初始化一个CURL的指针,对应销毁函数为curl_easy_cleanup
一般curl_easy_init意味着一个会话的开始. 它会返回一个easy_handle(CURL*对象)

销毁

void curl_easy_cleanup(CURL *handle);
这个调用用来结束一个会话,清理资源,与curl_easy_init配合着用.

设置参数

CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter); 这个是非常重要的函数,通过这个函数,我们来定义会话的各种行为

参数 含义
CURLOPT_URL 访问的url
CURLOPT_WRITEFUNCTION 回调函数

运行

CURLcode curl_easy_perform(CURL *handle);
启动会话
示例:

#include<string>
#include "curl\curl.h"
#include <iostream>
#include<vector>
using namespace std;

// UTF-8转std::string
std::string UTF8_To_string(const std::string& str)
{
	int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
	wchar_t* pwBuf = new wchar_t[nwLen + 1];    //一定要加1,不然会出现尾巴 
	memset(pwBuf, 0, nwLen * 2 + 2);
	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);
	int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
	char* pBuf = new char[nLen + 1];
	memset(pBuf, 0, nLen + 1);
	WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string strRet = pBuf;

	delete[]pBuf;
	delete[]pwBuf;
	pBuf = NULL;
	pwBuf = NULL;

	return strRet;
}

// std::string转UTF8
std::string string_To_UTF8(const std::string& str)
{
	int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
	wchar_t* pwBuf = new wchar_t[nwLen + 1];    //一定要加1,不然会出现尾巴 
	ZeroMemory(pwBuf, nwLen * 2 + 2);
	::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);
	int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
	char* pBuf = new char[nLen + 1];
	ZeroMemory(pBuf, nLen + 1);
	::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string strRet(pBuf);

	delete[]pwBuf;
	delete[]pBuf;
	pwBuf = NULL;
	pBuf = NULL;

	return strRet;
}

//回调函数
size_t WriteGetResp(void* buffer, size_t size, size_t nmemb, void *userp)
{
	//wchar_t tt = (wchar_t)buffer;
	//((string*)userp)->append(buffer, 0, size*nmemb);
	((std::string*)userp)->append(
		reinterpret_cast<char*>(buffer), size * nmemb);
	return size*nmemb;
}

//发送get请求
int HttpGet(char* url)
{
	string respData;
	CURL* curl;
	CURLcode res;

	curl = curl_easy_init();
	if (curl == NULL)
	{
		return 1;
	}
	
	curl_easy_setopt(curl, CURLOPT_URL, url);   //设置url
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteGetResp);    //设置回调函数
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &respData);   //设置目标字符串

	res = curl_easy_perform(curl);
	if (res != CURLE_OK)
	{
		cout << curl_easy_strerror(res) << endl;
	}

	curl_easy_cleanup(curl);
	respData = UTF8_To_string(respData);    //网络传输的字节流一般是utf8,需要自己转换,否则会出现中文乱码(libcurl只关注传输字节)
	cout << respData << endl;
	return 0;
}

int main() {
	HttpGet("https://www.baidu.com");
	return 0;
}