关于c++:高性能-C-HTTP-客户端原理与实现

62次阅读

共计 2936 个字符,预计需要花费 8 分钟才能阅读完成。

一、什么是 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 往往还有许多其余的需要,这里能够结合实际状况与大家分享:

  1. 联合 workflow 的串并联工作流,实现超大规模 并行抓取
  2. 按程序 或者按指定速度申请某个站点的内容,防止申请过猛被封禁;
  3. Http Client遇到 redirect 能够主动帮我做跳转,一步到位申请到最终后果;
  4. 心愿通过 proxy 代理拜访 HTTPHTTPS资源;

以上这些需要,要求框架对于 Http 工作的编排有超高的灵活性,以及对理论需要(比方 redirect、ssl 代理等性能)有十分接地气的反对,这些 Workflow 都曾经实现。

我的项目地址

https://github.com/sogou/workflow

欢送应用 workflowstar 反对一下!

正文完
 0