一、什么是 Http Client
Http协定,是全互联网独特的语言,而 Http Client,能够说是咱们须要从互联网世界获取数据的最根本办法,它实质上是一个URL 到一个 网页 的转换过程。而有了根本的 Http 客户端性能,再搭配上咱们想要的规定和策略,上至内容检索下至数据分析都能够实现了。
继上一次介绍用 Workflow 能够 10 行 C ++ 代码实现一个高性能 Http 服务器,明天持续给大家用 C ++ 实现一个高性能的 Http 客户端也同样很简略!
// [http_client.cc]
#include "stdio.h"
#include "workflow/HttpMessage.h"
#include "workflow/WFTaskFactory.h"
int main (int argc, char *argv[])
{
const char *url = "https://github.com/sogou/workflow";
WFHttpTask *task = WFTaskFactory::create_http_task (url, 2, 3,
[](WFHttpTask * task) {
fprintf(stderr, "%s %s %s\r\n",
task->get_resp()->get_http_version(),
task->get_resp()->get_status_code(),
task->get_resp()->get_reason_phrase());
});
task->start();
getchar(); // press "Enter" to end.
return 0;
}
只有装置好了 Workflow,以上代码即能够通过以下命令编译出一个简略的 http_client:
g++ -o http_client http_client.cc --std=c++11 -lworkflow -lssl -lcrypto -lpthread
依据 Http 协定,咱们执行这个可执行程序 ./http_client
,就会失去以下内容:
HTTP/1.1 200 OK
同理,咱们还能够通过其余 api 来取得返回的其余 Http header 和 Http body,所有内容都在这个 WFHttpTask
中。而因为 Workflow 是个异步调度框架,因而这个工作收回之后,不会阻塞以后线程,外加外部自带的连贯复用,从根本上保障了咱们的 Http Client 的高性能。
接下来给大家具体解说一下原理~
二、申请的过程
1. 创立 Http 工作
上述 demo 能够看到,申请是通过发动一个 Workflow 的 Http 异步工作来实现的,创立工作的接口如下:
WFHttpTask *create_http_task(const std::string& url,
int redirect_max, int retry_max,
http_callback_t callback);
第一个参数就是咱们要申请的 URL。对应的,在一开始的示例中,咱们的重定向次数redirect_max 是 2 次,而重试次数 retry_max 是 3 次。第四个参数是一个回调函数,示例中咱们用了一个 lambda,因为 Workflow 的工作都是异步的,因而咱们处理结果这件事件是被动告诉咱们的,后果回来就会调起这个回调函数,格局如下:
using http_callback_t = std::function<void (WFHttpTask *)>;
2. 填写 header 并收回
咱们的网络交互无非是 申请 - 回复 ,对应到Http Client 上,在咱们创立好了 task 之后,咱们有一些机会是解决 申请 的,在 Http 协定里,就是在 header 里填好协定相干的事件,比方咱们能够通过 Connection 来指定心愿失去建设 Http 的 长连贯 ,以节俭下次建设连贯的耗时,那么咱们能够把Connection 设置为Keep-Alive。示例如下:
protocol::HttpRequest *req = task->get_req();
req->add_header_pair("Connection", "Keep-Alive");
task->start();
最初咱们会把设置好申请的工作,通过 task->start();
收回。最开始的 http_client.cc
示例中,有一个 getchar();
语句,是因为咱们的异步工作收回后是非阻塞的,以后线程不临时停住就会退出,而咱们心愿等到回调函数回来,因而咱们能够用多种暂停的形式。
3. 解决返回后果
一个返回后果,依据 Http 协定,会蕴含三局部:音讯行 、 音讯头 header、音讯注释 body。如果咱们想要获取 body,能够这样:
const void *body;
size_t body_len;
task->get_resp()->get_parsed_body(&body, &body_len);
三、高性能的根本保障
咱们应用 C ++ 来写 Http Client,最香的就是能够利用其高性能。Workflow 对高并发是如何保障的呢?其实就两点:
- 纯异步;
- 连贯复用;
前者是对 线程资源 的反复利用、后者是对 连贯资源 的反复利用,这些框架层级都为用户治理好了,充沛缩小开发者的心智累赘。
1. 异步调度模式
同步和异步的模式间接决定了咱们的 Http Client 能够有多大的并发度。为什么呢?通过下图能够先看看同步框架发动三个 Http 工作,线程模型是怎么的:
网络提早往往十分大,如果咱们在同步期待工作回来的话,线程就会始终被占用。这时候咱们须要看看异步框架是如何实现的:
如图所示,只有工作收回之后,线程即可做其余事件,咱们传入了一个 回调函数 做异步告诉,因而等工作的网络回复收完之后,再让线程执行这个回调函数即可拿到 Http 申请的后果,期间多个工作并发进来的时候,线程是能够复用的,轻松达到几十万的 QPS 并发度。
2. 连贯复用
咱们方才有提到,只有咱们建设了长连贯,即可提高效率。为什么呢?因为框架对连贯有复用。咱们先来看看如果一个申请就建设一个连贯,会是什么样的状况:
很显然,占用大量的连贯是对系统资源的节约,而且每次都要做 connect 以及 close 是十分耗时的,除了 TCP 常见的握手以外,许多应用层协定建设连贯的过程也会绝对简单。但应用 Workflow 就不会有这样的懊恼,Workflow会在工作收回的时候主动查找以后能够复用的连贯,如果没有才会主动创立,齐全不须要开发者关怀连贯如何复用的细节:
3. 解锁其余性能
当然,除了以上的高性能以外,一个高性能的 Http Client 往往还有许多其余的需要,这里能够结合实际状况与大家分享:
- 联合 workflow 的串并联工作流,实现超大规模 并行抓取;
- 按程序 或者按指定速度申请某个站点的内容,防止申请过猛被封禁;
- Http Client遇到 redirect 能够主动帮我做跳转,一步到位申请到最终后果;
- 心愿通过 proxy 代理拜访
HTTP
与HTTPS
资源;
以上这些需要,要求框架对于 Http 工作的编排有超高的灵活性,以及对理论需要(比方 redirect、ssl 代理等性能)有十分接地气的反对,这些 Workflow 都曾经实现。
我的项目地址
https://github.com/sogou/workflow
欢送应用 workflow 并 star 反对一下!