初识 libcurl multi:实现一个 http 请求处理客户端,一个线程玩命发一个线程吐血收

本文介绍了如何使用 libcurl multi 接口设计一个高性能的 http 请求客户端,采用两个线程,一个负责批量发送请求,另一个处理响应。通过分析 libcurl 官方示例 10-at-a-time.c,提出并实现两种方案,讨论了线程间数据同步和并发安全性问题。最后总结了 libcurl multi 的理解和应用。
摘要由CSDN通过智能技术生成

一、引言

最近在工作中,遇到了这么一个需求:

我们希望拥有一个高性能的 http 请求处理客户端程序,这个客户端要求有这样的架构:

  1. 它拥有两个线程
  2. 一个线程接收业务程序通过消息队列发来的批量的 http 请求信息,进行批量的 http 请求
  3. 另一个线程接收外部的 http 应答,并将应答信息放到本地的消息队列中供业务程序使用
  4. 要求在 http 请求的处理过程中,尽量保持不阻塞高性能处理

这个需求的框架图大概是这个样子:

n 个业务程序 http client n 个 http 服务端程序 消息队列:发送批量的 http 请求报文 libcurl multi: 发起批量的 http 请求 libcurl multi: 处理批量的 http 应答 消息队列:转发 http 服务端的应答报文 n 个业务程序 http client n 个 http 服务端程序

可以看到,我们的需求,其实就是满足平台中大量的业务程序的 http 请求处理需求。其中业务程序自然不止一个,业务程序要请求的 http 服务端也不止一个,我们要做的 http 请求客户端程序实际上就像一个网关中间层。

那么现在问题来了,如果做到 http client 程序的高性能处理。我们当然不想它请求一次就阻塞掉,这样会非常非常的慢;我们也不想让处理应答这种耗时的操作占用太多时间,这样也会非常非常的慢。

此时,我想到了当初学习 libcurl 的时候在官网上读到的那句话:

The multi interface allows a single-threaded application to perform the same kinds of multiple, simultaneous transfers that multi-threaded programs can perform. It allows many of the benefits of multi-threaded transfers without the complexity of managing and synchronizing many threads.

尤其是最关键的执行请求的那个函数 curl_multi_perform 函数是异步的:

curl_multi_perform is asynchronous. It will only perform what can be done now and then return back control to your program. It is designed to never block. You need to keep calling the function until all transfers are completed.

这个接口非常适合用于我们现在的需求场景里面,当 http client 发起批量的 http 请求的时候,使用 libcurl multi 接口就可以实现不阻塞式异步处理。

那么如何设计和实现呢?

这里,我通过参考 libcurl 的官方示例 10-at-a-time.c 的代码框架,设计实现了两个设计方案(思路略有不同)的实现;并且因为工作环境的 libcurl 是老版本的库(没有 curl_multi_wait 函数的版本)而同时实现了新版本(使用 curl_multi_wait)的代码和旧版本(没有 curl_multi_wait 函数的版本)的代码。

接下来让我们开始吧:)

ps:
1. 10-at-a-time.c 官方示例代码网址 https://curl.haxx.se/libcurl/c/10-at-a-time.html
2. 本篇博客中所有的实现代码托管在 GitHub 上,仓库地址 https://github.com/wangying2016/libcurl_multi_http_client

二、分析:10-at-a-time.c 到底实现了什么

在设计实现我们自己的 http client 程序之前,我们先要来看看这个让我们启发很大的官方示例 demo 10-at-a-time.c 到底实现了什么。

根据 libcurl 的版本不同,10-at-a-time.c 的代码也稍有不同,这里我只分析最新的使用 curl_multi_wait 函数的版本(这一版本的代码也相当简洁),思路都是一样的,只是实现方式不一样(如果你跟我一样,也要考虑兼容老版本的 libcurl,那么建议你去官网上下载一个 curl-7.20.0.tar,进去里面的 docs/examples/10-at-a-time.c 中去看看老版本的实现方式)。

这里大家可以通过网址 https://curl.haxx.se/libcurl/c/10-at-a-time.html 点击进去阅读 10-at-a-time.c 的代码。我这里简单分析下这个程序的设计。

1. 10-at-a-time.c 程序功能

通过编译:

$ gcc -o 10-at-a-time 10-at-a-time.c -lcurl

你就可以拿到 10-at-a-time 的执行文件:

$ ./10-at-a-time

你就可以发现,这个程序实现了大量的 http 请求功能。具体并发量是多少呢?10,这也是它的名字的来源。

那么它是怎么实现的呢?

2. 10-at-a-time.c 框架分析

这里我也不浪费口舌,直接上流程图(细节比如说 transfers 是否小于当前全部 url 总数、获取消息是否处理成功等等判断未体现在流程图中,可自行仔细研读代码):

外层循环
使用 curl_multi_perform 批量发起 http 请求,使用 curl_multi_wait 轮询全部请求 handle 可读状态。外层循环主要是在发起请求,并且轮询请求 handle 状态。

Created with Raphaël 2.2.0
好的,以下是一个可以自定义请求头的libcurl示例代码,可以用于HTTPHTTPS请求: ```c #include <stdio.h> #include <curl/curl.h> int main(void) { CURL *curl; CURLcode res; struct curl_slist *headers = NULL; curl = curl_easy_init(); if(curl) { // 设置请求头 headers = curl_slist_append(headers, "Content-Type: application/json"); headers = curl_slist_append(headers, "Authorization: Bearer TOKEN"); // 设置请求地址 curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/api"); // 设置请求头 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // 执行请求 res = curl_easy_perform(curl); // 检查错误 if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); // 释放请求头内存 curl_slist_free_all(headers); // 清理curl句柄 curl_easy_cleanup(curl); } return 0; } ``` 这个示例代码中,我们首先创建了一个`curl_slist`类型的变量`headers`,用于存储请求头信息。然后使用`curl_slist_append`函数添加了两个请求头信息,即Content-Type和Authorization,并将`headers`作为选项传递给了`curl_easy_setopt`函数。 使用`curl_easy_setopt`函数设置了请求地址,然后使用`curl_easy_perform`函数执行请求。执行完请求后,我们使用`curl_slist_free_all`函数释放了请求头内存,并使用`curl_easy_cleanup`函数清理了curl句柄。 你可以根据自己的需求修改请求头信息。此外,你还可以使用`curl_easy_setopt`函数设置其他选项,如请求方式、请求体等。有关更多信息,请参阅libcurl文档。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值