在上一节课,我讲了 JSON、MessagePack 和 ProtoBuffer 这三种数据交换格式。现在,我们手里有了这些跨语言、跨平台的通用数据,该怎么与外部通信交换呢?
你肯定首先想到的就是 Socket 网络编程,使用 TCP/IP 协议栈收发数据,这样不仅可以在本地的进程间通信,也可以在主机、机房之间异地通信。
大方向上这是没错的,但你也肯定知道,原生的 Socket API 非常底层,要考虑很多细节,比如 TIME_WAIT、CLOSE_WAIT、REUSEADDR 等,如果再加上异步就更复杂了。
虽然你可能看过、学过不少这方面的资料,对如何处理这些问题“胸有成竹”,但无论如何,像 Socket 建连 / 断连、协议格式解析、网络参数调整等,都要自己动手做,想要“凭空”写出一个健壮可靠的网络应用程序还是相当麻烦的。
所以,今天我就来谈谈 C++ 里的几个好用的网络通信库:libcurl、cpr 和 ZMQ,让你摆脱使用原生 Socket 编程的烦恼。
libcurl:高可移植、功能丰富的通信库
第一个要说的库是 libcurl,它来源于著名的curl 项目,也是 curl 的底层核心。
libcurl 经过了多年的开发和实际项目的验证,非常稳定可靠,拥有上百万的用户,其中不乏 Apple、Facebook、Google、Netflix 等大公司。
它最早只支持 HTTP 协议,但现在已经扩展到支持所有的应用层协议,比如 HTTPS、FTP、LDAP、SMTP 等,功能强大。
libcurl 使用纯 C 语言开发,兼容性、可移植性非常好,基于 C 接口可以很容易写出各种语言的封装,所以 Python、PHP 等语言都有 libcurl 相关的库。
因为 C++ 兼容 C,所以我们也可以在 C++ 程序里直接调用 libcurl 来收发数据。
在使用 libcurl 之前,你需要用 apt-get 或者 yum 等工具安装开发库:
apt-get install libcurl4-openssl-dev
虽然 libcurl 支持很多协议,但最常用的还是 HTTP。所以接下来,我也主要介绍 libcurl 的 HTTP 使用方法,这样对其他的协议你也可以做到“触类旁通”。
libcurl 的接口可以粗略地分成两大类:easy 系列和 multi 系列。其中,easy 系列是同步调用,比较简单;multi 系列是异步的多线程调用,比较复杂。通常情况下,我们用 easy 系列就足够了。
使用 libcurl 收发 HTTP 数据的基本步骤有 4 个:
使用 curl_easy_init() 创建一个句柄,类型是 CURL*。但我们完全没有必要关心句柄的类型,直接用 auto 推导就行。
使用 curl_easy_setopt() 设置请求的各种参数,比如请求方法、URL、header/body 数据、超时、回调函数等。这是最关键的操作。
使用 curl_easy_perform() 发送数据,返回的数据会由回调函数处理。
使用 curl_easy_cleanup() 清理句柄相关的资源,结束会话。
下面我用个简短的例子来示范一下这 4 步:
#include <curl/curl.h> // 包含头文件
auto curl = curl_easy_init(); // 创建CURL句柄
assert(curl);
curl_easy_setopt(curl, CURLOPT_URL, "http://nginx.org"); // 设置请求URI
auto res = curl_easy_perform(curl); // 发送数据
if (res != CURLE_OK) { // 检查是否执行成功
cout << curl_easy_s