C++异步网络库workflow入门教程(1)HTTP任务

简介: 创建任务方法原型在workflow中所有的客户端任务都放在`WFTaskFactory`工厂类中+ `url:`请求的http url+ `redirect_max:`表示最大重定向次数。如果在请求过程中遇到重定向,该参数指定了最多允许重定向的次数。+ `retry_max`:表示最大重试次数。如果请求失败,该参数指定了最多可以重试的次数。+ `callback`:这是一个回调函数的指针,用于处理请求的响应。原型为`using http_callback_t = std::function

如果觉得小弟写的可以,请给一个点赞+关注支持

workFlow c++异步网络库编译教程与简介

创建并启动http任务

示例

#include <workflow/WFFacilities.h>
int main(){
   
    WFHttpTask * httpTask = WFTaskFactory::create_http_task("http://baidu.com",0,0,0);
    protocol::HttpRequest *req =  httpTask->get_req();
    req->add_header_pair("Accept","*/*");
    req->add_header_pair("User-Agent","myHttpTask");
    req->set_header_pair("Connection","close");
    httpTask->start();
    pause();
}

创建任务方法原型

在workflow中所有的客户端任务都放在WFTaskFactory工厂类中,

  • url:请求的http url
  • redirect_max:表示最大重定向次数。如果在请求过程中遇到重定向,该参数指定了最多允许重定向的次数。
  • retry_max:表示最大重试次数。如果请求失败,该参数指定了最多可以重试的次数。
  • callback:这是一个回调函数的指针,用于处理请求的响应。原型为using http_callback_t = std::function<void (WFHttpTask *)>;说白了,就是一个参数为Task本身,没有返回值的函数。这个callback可以传NULL,表示无需callback。我们一切任务的callback都是这个风格。
#include "workflow/WFTaskFactory.h"
class WFTaskFactory
{
   
public:
    static WFHttpTask *create_http_task(const std::string& url,
                                        int redirect_max,
                                        int retry_max,
                                        http_callback_t callback);
}

代码解析

  1. 需要说明的是,所有工厂函数不会返回失败,所以不用担心task为空指针,哪怕是url不合法。一切错误都在callback再处理。
  2. httpTask->get_req()函数得到任务的request,默认是GET方法,HTTP/1.1长连接。框架会自动加上request_uri,Host等。
  3. 框架会在发送前根据需要自动加上Content-Length或Connection这些http header。用户也可以通过add_header_pair()方法添加自己的header。
  4. 关于http消息的更多接口,可以在HttpMessage.h中查看。
  5. httpTask->start()启动任务,非阻塞,并且不会失败。之后callback必然会在被调用。因为异步的原因,start()以后显然不能再用httpTask指针了。
  6. 为了让示例尽量简单,start()之后调用pause()防止程序退出,用户需要Ctrl-C结束程序。

处理http抓取结果

示例代码

首先,先看一眼示例代码

#include <workflow/WFFacilities.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>

void callback(WFHttpTask *httpTask){
   
    //在回调函数中,可以获取任务的所有信息的
    protocol::HttpRequest *req =  httpTask->get_req();
    protocol::HttpResponse *resp = httpTask->get_resp();
    int state = httpTask->get_state();
    int error = httpTask->get_error();
    switch (state)
    {
   
    case WFT_STATE_SYS_ERROR:
        fprintf(stderr,"system error: %s\n", strerror(error));
        break;
    case WFT_STATE_DNS_ERROR:
        fprintf(stderr,"dns error: %s\n", gai_strerror(error));
        break;
    case WFT_STATE_SUCCESS:
        break;
    }
    if(state != WFT_STATE_SUCCESS){
   
        fprintf(stderr,"Failed\n");
        return;
    }
    else{
   
        fprintf(stderr,"Success!\n");
    }

    fprintf(stderr,"request\r\n %s %s %s\r\n", req->get_method(),
                                               req->get_request_uri(),
                                               req->get_http_version());

    //使用迭代器来遍历首部字段
    std::string name;
    std::string value;
    protocol::HttpHeaderCursor reqCursor(req);
    while(reqCursor.next(name,value)){
   
        fprintf(stderr,"%s:%s\r\n",name.c_str(),value.c_str());
    }
    fprintf(stderr,"\r\n");

    fprintf(stderr,"response\r\n %s %s %s\r\n", resp->get_http_version(),
                                                resp->get_status_code(),
                                                resp->get_reason_phrase());
    protocol::HttpHeaderCursor respCursor(resp);
    while(respCursor.next(name,value)){
   
        fprintf(stderr,"%s:%s\r\n",name.c_str(),value.c_str());
    }
    fprintf(stderr,"\r\n");

    //print response body
    const void *body;
    size_t size;
    resp->get_parsed_body(&body,&size);
    //get_parsed_body方法会修改指针变量body的指向
    fwrite(body,1,size,stderr);                                   
}
//异步+回调
int main(){
   
    signal(SIGINT,sigHandler);
    WFHttpTask * httpTask = WFTaskFactory::create_http_task("http://baidu.com",0,0,callback);
    protocol::HttpRequest *req =  httpTask->get_req();
    req->add_header_pair("Accept","*/*");
    req->add_header_pair("User-Agent","myHttpTask");
    req->set_header_pair("Connection","close");
    httpTask->start();
    pause();
}

代码解析

  • 在这个callback里,httpTask就是我们通过工厂产生的httpTask。
  • httpTask->get_req()得到任务的request,是HttpMessage类的派生。
    • req->get_method():获取请求方法,这里返回GET
    • req->get_request_uri() :请求url,这里返回http://baidu.com
    • req->get_http_version():http版本,默认HTTP1.1
  • httpTask->get_resp()得到任务的response,这个和request区别不大,都是HttpMessage的派生。
    • resp->get_parsed_body(&body,&size)获取http响应体,通过传入void*的地址,也就是传入二级指针以及size参数地址,,内部修改void*指针的指向以及size值,将其指向内部隐藏的响应体和大小,
    • 这个调用得到的是原始的http body,不解码chunk编码。如需解码chunk编码,可使用HttpUtil.h里的
  • httpTask->get_state()httpTask->get_error()分别获得任务的运行状态和错误码。
    • WFT_STATE_SUCCESS表示运行正常,没有异常
    • WFT_STATE_DNS_ERROR表示出现dns错误,一般是url写错了
    • WFT_STATE_SYS_ERROR表示出现系统错误,
  • 通过HttpHeaderCursor对象,对requestresponseheader进行扫描。获取响应头,在HttpUtil.h可以看到Cursor的定义。
class HttpHeaderCursor
{
   
public:
    HttpHeaderCursor(const HttpMessage *message);
    ...
    void rewind();
    ...
    bool next(std::string& name, std::string& value);
    bool find(const std::string& name, std::string& value);
    ...
};

相信这个cursor在使用上应该不会有什么疑惑。

HttpChunkCursor。 另外需要说明的是,find()接口会修改cursor内部的指针,即使用过find()过后如果仍然想对header进行遍历,需要通过rewind()接口回到cursor头部。

目录
相关文章
|
9月前
|
C++
基于Reactor模型的高性能网络库之地址篇
这段代码定义了一个 InetAddress 类,是 C++ 网络编程中用于封装 IPv4 地址和端口的常见做法。该类的主要作用是方便地表示和操作一个网络地址(IP + 端口)
371 58
|
9月前
|
网络协议 算法 Java
基于Reactor模型的高性能网络库之Tcpserver组件-上层调度器
TcpServer 是一个用于管理 TCP 连接的类,包含成员变量如事件循环(EventLoop)、连接池(ConnectionMap)和回调函数等。其主要功能包括监听新连接、设置线程池、启动服务器及处理连接事件。通过 Acceptor 接收新连接,并使用轮询算法将连接分配给子事件循环(subloop)进行读写操作。调用链从 start() 开始,经由线程池启动和 Acceptor 监听,最终由 TcpConnection 管理具体连接的事件处理。
290 2
|
9月前
基于Reactor模型的高性能网络库之Tcpconnection组件
TcpConnection 由 subLoop 管理 connfd,负责处理具体连接。它封装了连接套接字,通过 Channel 监听可读、可写、关闭、错误等
243 1
|
9月前
|
负载均衡 算法 安全
基于Reactor模式的高性能网络库之线程池组件设计篇
EventLoopThreadPool 是 Reactor 模式中实现“一个主线程 + 多个工作线程”的关键组件,用于高效管理多个 EventLoop 并在多核 CPU 上分担高并发 I/O 压力。通过封装 Thread 类和 EventLoopThread,实现线程创建、管理和事件循环的调度,形成线程池结构。每个 EventLoopThread 管理一个子线程与对应的 EventLoop(subloop),主线程(base loop)通过负载均衡算法将任务派发至各 subloop,从而提升系统性能与并发处理能力。
469 3
|
9月前
基于Reactor模式的高性能网络库github地址
https://github.com/zyi30/reactor-net.git
205 0
|
9月前
基于Reactor模型的高性能网络库之Poller(EpollPoller)组件
封装底层 I/O 多路复用机制(如 epoll)的抽象类 Poller,提供统一接口支持多种实现。Poller 是一个抽象基类,定义了 Channel 管理、事件收集等核心功能,并与 EventLoop 绑定。其子类 EPollPoller 实现了基于 epoll 的具体操作,包括事件等待、Channel 更新和删除等。通过工厂方法可创建默认的 Poller 实例,实现多态调用。
410 60
|
9月前
基于Reactor模型的高性能网络库之Channel组件篇
Channel 是事件通道,它绑定某个文件描述符 fd,注册感兴趣的事件(如读/写),并在事件发生时分发给对应的回调函数。
402 60
|
7月前
|
存储 网络协议 算法
从HPACK到多路复用,揭秘HTTP/2如何终结网络拥堵
HTTP/2通过HPACK压缩头部冗余信息,提升传输效率;并利用多路复用技术,在单个TCP连接上并行处理多个请求,避免队头阻塞,显著提升性能。同时支持服务器推送和流优先级设置,优化资源加载体验。
442 7
|
9月前
|
安全 调度
基于Reactor模型的高性能网络库之核心调度器:EventLoop组件
它负责:监听事件(如 I/O 可读写、定时器)、分发事件、执行回调、管理事件源 Channel 等。
434 57
|
9月前
基于Reactor模型的高性能网络库之时间篇
是一个用于表示时间戳(精确到微秒)**的简单封装类
283 57