常见的使用c/c++进行http/https请求的方案
- libcurl库
libcurl是一个开源的网络数据传输库,支持http、https、ftp等协议,可以在各种操作系统上使用。 - libevent库
libevent是一个事件驱动的网络编程库,可以处理多个网络连接和套接字,支持http、https等协议。 - boost库
boost是一个C++库集合,也包含了网络编程库,可以实现http/https请求 - Qt库
Qt是一个跨平台的应用程序开发框架,包含了网络编程库,可以实现http/https请求 - socket编程
使用socket编程可以手动实现http/https请求,但要自己处理http/https协议的细节
实际应用中使用libcurl库是最常见、最方便的实现http/https请求的方案
libcurl
源码下载
libcurl库在默认情况下已经包含了大部分需要的功能,但是如果需要使用某些特定的功能,可能需要依赖一些第三方库。以下是一些常见的libcurl依赖的第三方库:
第三方库 | 说明 |
---|---|
OpenSSL | 用于支持https协议 |
GnuTLS | 用于支持https协议 |
NSS | 用于支持https协议 |
wolfSSL | 用于支持https协议 |
mbed TLS | 用于支持https协议 |
zlib | 用于支持HTTP响应数据的压缩和解压缩 |
OpenLDAP | 用于支持轻量目录访问协议 |
heimdal | 提供对GSS-API的支持,用于在libcurl中提供Kerberos和SPNEGO身份验证 |
MIT Kerberos | 提供对GSS-API的支持,用于在libcurl中提供Kerberos和SPNEGO身份验证 |
nghttp2 | 用于支持HTTP/2协议 |
c-ares | 用于支持异步DNS解析,可以提高网络请求的性能 |
libidn2 | 用于支持国际化域名(IDN),如.CN、.TW、.ORG等域名 |
libssh2 | 用于支持SSH协议,可以用于SFTP、SCP等文件传输协议 |
不同版本的libcurl库可能会依赖不同的第三方库,具体依赖关系可以查看对应版本的文档。在编译和安装libcurl库时,需要确保依赖的第三方库已经安装,并且需要使用相应的编译选项来启用对应的功能
此处使用Openssl和zlib与libcurl进行交叉编译,libcurl默认为最新版
编译
zlib编译
版本:1.2.12
该版本的configure不支持设置--host项,因此需要手动更改Makefile,打开Makefile文件,将其中的CC、AR、RANLIB都修改为arm-linux交叉编译器的相关参数
操作顺序
./configure --prefix=安装目录
修改Makefile
make
make install
openssl编译
版本:OpenSSL 1.1.x
操作顺序
./Configure \
CROSS_COMPILE=/opt/gccenv/arm4.5.1/bin/arm-none-linux-gnueabi- \
--prefix=/home/dcb/code/log/3rdParty/openssl/output \
linux-armv4 no-asm shared
make
make install
libcurl编译
版本:官网最新
操作顺序
./configure --prefix=/home/dcb/code/log/3rdParty/curl/output \
--host=arm-none-linux-gnueabi \
CC=/opt/gccenv/arm4.5.1/bin/arm-none-linux-gnueabi-gcc \
--with-openssl=/home/dcb/code/log/3rdParty/openssl/output/ \
--with-zlib=/home/dcb/code/log/3rdParty/zlib/output/ \
--enable-shared=1
make
make install
证书生成
除了在编译libcurl时添加对https的支持,还需要配置证书,以下为生成自签名证书相关
openssl req -x509 -newkey rsa:4096 -keyout mycert.pem -out mycert.pem -days 365 -nodes
应用
将编译的openssl,zlib和libcurl头文件和库文件放到对应的工程中
main.cpp
#include <iostream>
#include <sstream>
#include <string.h>
#include "include/curl/curl.h"
using namespace std;
size_t ReceiveData(void *buffer, size_t size, size_t nmemb, void *stream);
string PostToHost(const char *url, const char *data, CURLcode *res);
int main()
{
string url = "https://www.cnblogs.com/";
string data = "";
string reply;
CURLcode code;
reply = PostToHost(url.c_str(), data.c_str(), &code);
cout << "CURLcode: " << code << endl;
cout << reply << endl;
return 0;
}
size_t ReceiveData(void *buffer, size_t size, size_t nmemb, void *stream)
{
string data((const char *)buffer, (size_t)size * nmemb);
*((stringstream *)stream) << data << endl;
return size * nmemb;
}
string PostToHost(const char *url, const char *data, CURLcode *res)
{
CURL *curl;
char len[32] = {0};
struct curl_slist *headers = NULL;
curl = curl_easy_init();
if (!curl) {
*res = CURLE_FAILED_INIT;
cout << __FUNCTION__ << " " << __LINE__ << " CURL INIT FALIED" << endl;
return "";
}
std::stringstream out;
headers = curl_slist_append(headers, "Accept: application/json");
snprintf(len, sizeof(len), "Content-Length:%d", (int)strlen(data));
headers = curl_slist_append(headers, len);
headers = curl_slist_append(headers, "charset: UTF-8");
headers = curl_slist_append(headers, "Expect:");
struct curl_slist *p = headers;
while(p->next != NULL){
printf("headers: %s\n",p->data);
p = p->next;
}
// 设置请求体(post) get请求可以不用设置这个参数
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
// 输出详细信息用户调试
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
// 设置请求url
curl_easy_setopt(curl, CURLOPT_URL, url);
// 设置请求头
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// 设置回调函数,当http服务器有数据返回时调用这个回调函数
// 回调函数必须以下面的函数为原型
// size_t function( char *ptr, size_t size, size_t nmemb, void *userdata);
// 被调用ptr指向的数据由size*nmemb(乘积)获得
// 若不设置此回调函数,默认将接收的数据返回到终端
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ReceiveData);
// 指定第三个参数作为“CURLOPT_WRITEFUNCTION” 回调函数的第四个参数
// 若不使用回调函数保存数据,则此部分的第三个参数必须为FILE指针,
// 函数会将接收到的数据自动写入到这个FILE指针指向的文件流中
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out);
// 设置为非零值
// 否则POST是普通的 application/x-www-from-urlencoded 类型
curl_easy_setopt(curl, CURLOPT_POST, 1);
// 设置连接主机的最长等待时间
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
// 设置整个cURL函数执行的时间(包含连接等待时间
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20);
// CURLOPT_HEADER: 若把一个头包含在输出中,则设置为1。
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
// 若设置为1,则会跟踪爬去重定向页面
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
// 0:禁止 cURL 验证对等证书
// 1:验证证书,要验证的证书在CURLOPT_CAINFO 中设置或CURLOPT_CAPATH中设置证书目录
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSLVERSION, 4);
// 配置 https 请求所需证书
curl_easy_setopt(curl, CURLOPT_SSLCERT, "./ce/mycert.pem");
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl, CURLOPT_SSLKEY, "./ce/mycert.pem");
curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
*res = curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return out.str();
}