11.王道_workflow

  • 如何部署http服务器
    • 从零开始
    • 使用开源的产品
      • nginx,apache
    • 库 or 框架
      • workflow
      • boost::asio(TCP),workflow
      • boost::beast(HTTP)(基于asio)

服务器类型

  1. 原始的多进程服务器(以Apache为例)

  2. 事件驱动服务器(Event-Driven)
    在这里插入图片描述
    在这里插入图片描述

  3. 异步回调模型(Asynchronous Callback)
    在这里插入图片描述
    在这里插入图片描述

  • sql语句的执行
    • 事件驱动模型:准备工作和返回结果分为两个事件。
    • 异步回调模型:准备的sql语句作为任务的准备工作,读到以后的事情作为回调函数。
    • 协程:从头写到尾部。

workflow简介

在这里插入图片描述

安装workflow

在这里插入图片描述
在这里插入图片描述

workflow是一种异步框架

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


#include <54func.h>
#include <workflow/WFFacilities.h>

static WFFacilities::WaitGroup gWaitGroup(1);  // 计数器

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done(); //计数器减一
}
// 阻塞主线程,直到按住Ctrl+C
int main()
{
    signal(SIGINT,handler);
    gWaitGroup.wait(); // 等待直到计数器减一f

    return 0;
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

使用workflow作为HTTP客户端

在这里插入图片描述

避免进程提前终止

在这里插入图片描述

http客户端的基本流程

  • 只有请求
#include <54func.h>
#include<iostream>
#include <workflow/WFFacilities.h>
#include<workflow/HttpMessage.h>
#include<workflow/HttpUtil.h>

using std::cout;
using std::endl;
static WFFacilities::WaitGroup gWaitGroup(1);  // 计数器

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done(); //计数器减一
}
// 阻塞主线程,直到按住Ctrl+C
int main()
{
    signal(SIGINT,handler);
    cout<<"1"<<endl;
    // 利用工厂函数创建一个任务
    WFHttpTask *httpTask = WFTaskFactory::create_http_task("http://10.102.1.35:1234",10,0,nullptr);
    // 设置httpTask的属性和请求
    cout<<"2"<<endl;
    protocol::HttpRequest *req = httpTask->get_req();
    req->add_header_pair("Accept","*/*");
    // 将任务派给框架,由g框架异步调用
    httpTask->start();
    cout<<"3"<<endl;
    gWaitGroup.wait(); // 等待直到计数器减一f
    return 0;
}

在这里插入图片描述

  • 输出3:立刻开始执行,异步的特点

  • 有请求有响应(重写回调函数)

#include <54func.h>
#include<iostream>
#include <workflow/WFFacilities.h>
#include<workflow/HttpMessage.h>
#include<workflow/HttpUtil.h>

using std::cout;
using std::endl;
static WFFacilities::WaitGroup gWaitGroup(1);  // 计数器

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done(); //计数器减一
}
// 有请求有响应

void httpCallback(WFHttpTask *httpTask)
{
    cout<<"4"<<endl;
}
// 阻塞主线程,直到按住Ctrl+C
int main()
{
    signal(SIGINT,handler);
    cout<<"1"<<endl;
    // 利用工厂函数创建一个任务
    WFHttpTask *httpTask = WFTaskFactory::create_http_task("http://10.102.1.35:1234",10,0,httpCallback);
    // 设置httpTask的属性和请求
    cout<<"2"<<endl;
    protocol::HttpRequest *req = httpTask->get_req();
    req->add_header_pair("Accept","*/*");
    // 将任务派给框架,由g框架异步调用
    httpTask->start();
    cout<<"3"<<endl;
    gWaitGroup.wait(); // 等待直到计数器减一f
    return 0;
}

注意这里的3和4的前后顺序不确定
在这里插入图片描述

#include <54func.h>
#include<iostream>
#include <workflow/WFFacilities.h>
#include<workflow/HttpMessage.h>
#include<workflow/HttpUtil.h>

using std::cout;
using std::endl;
static WFFacilities::WaitGroup gWaitGroup(1);  // 计数器

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done(); //计数器减一
}
// 有请求有响应

void httpCallback(WFHttpTask *httpTask)
{
    cout<<"4"<<endl;
    // 这里就可以处理响应的请求了
    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:   // 系统级的错误
        cout<<"系统级错误 :"<<strerror(error)<<endl;
        break;
    case WFT_STATE_DNS_ERROR:   // 网络连接出现问题
        cout<<"DNS Error: "<<gai_strerror(error)<<endl;
        break;
    case WFT_STATE_SUCCESS:     // 成功
        break;
    }

    if(state == WFT_STATE_SUCCESS)
    {
        cout<<"SUCCESS"<<endl;
    }
    else
    {
        cout<<"FAILS"<<endl;
    }
}
// 阻塞主线程,直到按住Ctrl+C
int main()
{
    signal(SIGINT,handler);
    cout<<"1"<<endl;
    // 利用工厂函数创建一个任务
    WFHttpTask *httpTask = WFTaskFactory::create_http_task("http://10.102.1.35:1234",10,0,httpCallback);
    // 设置httpTask的属性和请求
    cout<<"2"<<endl;
    protocol::HttpRequest *req = httpTask->get_req();
    req->add_header_pair("Accept","*/*");
    // 将任务派给框架,由g框架异步调用
    httpTask->start();
    cout<<"3"<<endl;
    gWaitGroup.wait(); // 等待直到计数器减一f
    return 0;
}
  • 不启动服务端时
    在这里插入图片描述

  • 启动服务端之后还是上面的报错。发现是没加入冒号
    在这里插入图片描述

  • 修改之后正确
    在这里插入图片描述

遍历首部字段

  • 由于首部字段比较小,所以workflow将请求和响应的首部字段放在一起

在这里插入图片描述

#include <54func.h>
#include<iostream>
#include<string>
#include <workflow/WFFacilities.h>
#include<workflow/HttpMessage.h>
#include<workflow/HttpUtil.h>

using std::cout;
using std::endl;
using std::string;

static WFFacilities::WaitGroup gWaitGroup(1);  // 计数器

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done(); //计数器减一
}
// 有请求有响应

void httpCallback(WFHttpTask *httpTask)
{
    cout<<"4"<<endl;
    // 这里就可以处理响应的请求了
    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:   // 系统级的错误
        cout<<"系统级错误 :"<<strerror(error)<<endl;
        break;
    case WFT_STATE_DNS_ERROR:   // 网络连接出现问题
        cout<<"DNS Error: "<<gai_strerror(error)<<endl;
        break;
    case WFT_STATE_SUCCESS:     // 成功
        break;
    }

    if(state == WFT_STATE_SUCCESS)
    {
        cout<<"SUCCESS"<<endl;
    }
    else
    {
        cout<<"FAILS"<<endl;
    }
    protocol::HttpHeaderCursor  cursorReq(req);
    string key,value;
    while(cursorReq.next(key,value))
    {
        cout<<"request key = "<<key<<" value: "<<value<<endl;
    }
    protocol::HttpHeaderCursor  cursorResp(resp);
    cout<<"______________________________"<<endl;
    while(cursorResp.next(key,value))
    {
        cout<<"response key = "<<key<<" value: "<<value<<endl;
    }
}
// 阻塞主线程,直到按住Ctrl+C
int main()
{
    signal(SIGINT,handler);
    cout<<"1"<<endl;
    // 利用工厂函数创建一个任务
    WFHttpTask *httpTask = WFTaskFactory::create_http_task("http://10.102.1.35:1234",10,0,httpCallback);
    // 设置httpTask的属性和请求
    cout<<"2"<<endl;
    protocol::HttpRequest *req = httpTask->get_req();
    req->add_header_pair("Accept","*/*");
    // 将任务派给框架,由g框架异步调用
    httpTask->start();
    cout<<"3"<<endl;
    gWaitGroup.wait(); // 等待直到计数器减一f
    return 0;
}

在这里插入图片描述

处理响应体

  • 由于响应体一般都很大,workflow单独保存一个地方
    在这里插入图片描述

  • 虽然body加const但是实际上一级指针是非const的

void httpCallback(WFHttpTask *httpTask)
{
    cout<<"4"<<endl;
    // 这里就可以处理响应的请求了
    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:   // 系统级的错误
        cout<<"系统级错误 :"<<strerror(error)<<endl;
        break;
    case WFT_STATE_DNS_ERROR:   // 网络连接出现问题
        cout<<"DNS Error: "<<gai_strerror(error)<<endl;
        break;
    case WFT_STATE_SUCCESS:     // 成功
        break;
    }

    if(state == WFT_STATE_SUCCESS)
    {
        cout<<"SUCCESS"<<endl;
    }
    else
    {
        cout<<"FAILS"<<endl;
    }
    protocol::HttpHeaderCursor  cursorReq(req);
    string key,value;
    while(cursorReq.next(key,value))
    {
        cout<<"request key = "<<key<<" value: "<<value<<endl;
    }
    protocol::HttpHeaderCursor  cursorResp(resp);
    cout<<"______________________________"<<endl;
    while(cursorResp.next(key,value))
    {
        cout<<"response key = "<<key<<" value: "<<value<<endl;
    }

    const void *body;
    size_t size;
    resp->get_parsed_body(&body,&size);
    cout<<string((char*)body,size)<<endl;
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

class HttpMessage : public ProtocolMessage
{
public:
    const char *get_http_version() const;
    bool set_http_version(const char *version);
    bool add_header_pair(const char *name, const char *value);
    bool set_header_pair(const char *name, const char *value);
    bool get_parsed_body(const void **body, size_t *size) const;
    /* Output body is for sending. Want to transfer a message received, maybe:
     * msg->get_parsed_body(&body, &size);
     * msg->append_output_body_nocopy(body, size); */
    bool append_output_body(const void *buf, size_t size);
    bool append_output_body_nocopy(const void *buf, size_t size);
    void clear_output_body();
    size_t get_output_body_size() const;
    // 上述接口都有std::string版本
    //...
};
class HttpRequest : public HttpMessage
{
public:
    const char *get_method() const;
    const char *get_request_uri() const;
    bool set_method(const char *method);
    bool set_request_uri(const char *uri);
    // 上述接口都有std::string版本
    //...
};
class HttpResponse : public HttpMessage
{
public:
    const char *get_status_code() const;
    const char *get_reason_phrase() const;
    bool set_status_code(const char *code);
    bool set_reason_phrase(const char *phrase);
    /* Tell the parser, it is a HEAD response. */
    void parse_zero_body();
    // 上述接口都有std::string版本
    //...
};

在这里插入图片描述

回调函数的设计

在这里插入图片描述


#include "unixHeader.h"
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
static WFFacilities::WaitGroup wait_group(1);
void sig_handler(int signo)
{
    wait_group.done();
}
void callback(WFHttpTask *httpTask)
{
    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. Press Ctrl-C to exit.\n");
        return;
    }
    fprintf(stderr, "success\n");
    wait_group.done();
}
int main(int argc, char *argv[])
{
    std::string url = "http://";
    url.append(argv[1]);
    signal(SIGINT, sig_handler);
    auto httpTask = WFTaskFactory::create_http_task(url, 0, 0, callback);
    protocol::HttpRequest *req = httpTask->get_req();
    req->add_header_pair("Accept", "*/*");
    req->add_header_pair("User-Agent", "TestAgent");
    req->add_header_pair("Connection", "close");
    httpTask->start();
    wait_group.wait();
    return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

redis任务与串行任务

redis任务的基本使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <54func.h>
#include<iostream>
#include<string>
#include <workflow/WFFacilities.h>
#include<workflow/HttpMessage.h>
#include<workflow/HttpUtil.h>

using std::cout;
using std::endl;
using std::string;

static WFFacilities::WaitGroup gWaitGroup(1);  // 计数器

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done(); //计数器减一
}


// 阻塞主线程,直到按住Ctrl+C
int main()
{
    signal(SIGINT,handler);
    cout<<"1"<<endl;
    // 利用工厂函数创建一个任务
    WFRedisTask *redisTask = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,nullptr);
    // 设置redisTask的属性和请求
    protocol::RedisRequest *req = redisTask->get_req();
    req->set_request("SET",{"x","54"});
    // 将任务派给框架,由g框架异步调用
    redisTask->start();
    gWaitGroup.wait(); // 等待直到计数器减一f
    return 0;
}

在这里插入图片描述

处理redis任务的结果

在这里插入图片描述


namespace protocol
{
    class RedisValue
    {
    public:
        // nil
        RedisValue();
        virtual ~RedisValue();
        // copy constructor
        RedisValue(const RedisValue &copy);
        // copy operator
        RedisValue &operator=(const RedisValue &copy);
        // move constructor
        RedisValue(RedisValue &&move);
        // move operator
        RedisValue &operator=(RedisValue &&move);
        // release memory and change type to nil
        void set_nil();
        void set_int(int64_t intv);
        void set_string(const std::string &strv);
        void set_status(const std::string &strv);
        void set_error(const std::string &strv);
        void set_string(const char *str, size_t len);
        void set_status(const char *str, size_t len);
        void set_error(const char *str, size_t len);
        void set_string(const char *str);
        void set_status(const char *str);
        void set_error(const char *str);
        // array(resize)
        void set_array(size_t new_size);
        // set data by C style data struct
        void set(const redis_reply_t *reply);
        // Return true if not error
        bool is_ok() const;
        // Return true if error
        bool is_error() const;
        // Return true if nil
        bool is_nil() const;
        // Return true if integer
        bool is_int() const;
        // Return true if array
        bool is_array() const;
        // Return true if string/status
        bool is_string() const;
        // Return type of C style data struct
        int get_type() const;
        // Copy. If type isnot string/status/error, returns an empty std::string
        std::string string_value() const;
        // No copy. If type isnot string/status/error, returns NULL.
        const std::string *string_view() const;
        // If type isnot integer, returns 0
        int64_t int_value() const;
        // If type isnot array, returns 0
        size_t arr_size() const;
        // If type isnot array, do nothing
        void arr_clear();
        // If type isnot array, do nothing
        void arr_resize(size_t new_size);
        // Always return std::vector.at(pos); notice overflow exception
        RedisValue &arr_at(size_t pos) const;
        // Always return std::vector[pos]; notice overflow exception
        RedisValue &operator[](size_t pos) const;
        // transform data into C style data struct
        bool transform(redis_reply_t *reply) const;
        // equal to set_nil();
        void clear();
        // format data to text
        std::string debug_string() const;
        //...
    };
}
  • 下面是使用redis读类型任务获取一系列结果的例子。
#include "unixHeader.h"
#include <workflow/RedisMessage.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
void redis_callback(WFRedisTask *task)
{
    protocol::RedisRequest *req = task->get_req();
    protocol::RedisResponse *resp = task->get_resp();
    int state = task->get_state();
    int error = task->get_error();
    protocol::RedisValue val;
    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:
        resp->get_result(val);
        if (val.is_error())
        {
            fprintf(stderr, "Error reply. Need a password?\n");
            state = WFT_STATE_TASK_ERROR;
        }
        break;
    }
    if (state != WFT_STATE_SUCCESS)
    {
        fprintf(stderr, "Failed. Press Ctrl-C to exit.\n");
        return;
    }
    if (val.is_array())
    {
        for (int i = 0; i < val.arr_size(); ++i)
        {
            auto ele = val.arr_at(i);
            fprintf(stderr, "REDIS HGETALL %d = %s\n", i,
                    ele.string_value().c_str());
        }
    }
}
static WFFacilities::WaitGroup wait_group(1);
void sig_handler(int signo)
{
    wait_group.done();
}
int main(int argc, char *argv[])
{
    signal(SIGINT, sig_handler);
    url = "redis://127.0.0.1:6379";
    WFRedisTask *task;
    = WFTaskFactory::create_redis_task(data.url, 2,
                                       redis_callback);
    protocol::RedisRequest *req = task->get_req();
    // req->set_request("HSET", { "HMAP1","key1", "value1" });
    req->set_request("HGETALL", {"HMAP1"});
    task->start();
    wait_group.wait();
    return 0;
}
  • 读取结果

#include <54func.h>
#include<iostream>
#include<string>
#include <workflow/WFFacilities.h>
#include<workflow/HttpMessage.h>
#include<workflow/HttpUtil.h>

using std::cout;
using std::endl;
using std::string;

static WFFacilities::WaitGroup gWaitGroup(1);  // 计数器

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done(); //计数器减一
}
// 阻塞主线程,直到按住Ctrl+C
int main()
{
    signal(SIGINT,handler);
    cout<<"1"<<endl;
    // 利用工厂函数创建一个任务
    WFRedisTask *redisTask = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,
                                                              [](WFRedisTask *redisTask){
                                                              protocol::RedisRequest *req = redisTask->get_req();
                                                              protocol::RedisResponse *resp = redisTask->get_resp();
                                                                                                                          protocol::RedisValue value ; // 获取redis返回的结果
                                                              int state  = redisTask->get_state();
                                                              int error = redisTask->get_error();
                                                              // error只能处理网络连接和系统错误,语法错误只能通过返回结果查看oo
                                                                                                                          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:
                                                                                                                                        resp->get_result(value);  // 语法错误只能通过返回结果进行查看
                                                                                                                                        if(value.is_error())
                                                                                                                                        {
                                                                                                                                                cout<<"语法错误"<<endl;
                                                                                                                                                state = WFT_STATE_TASK_ERROR; // 任务层面的错误
                                                                                                                                        }
                                                                                                                                        break;
                                                                                                                          }
                                                                                                                          if (state != WFT_STATE_SUCCESS)
                                                                                                                          {
                                                                                                                                        fprintf(stderr, "Failed. Press Ctrl-C to exit.\n");
                                                                                                                                        return;
                                                                                                                          }
                                                              if(value.is_string())
                                                              {
                                                                  cout<<"value is a string , value = "<<value.string_value()<<endl;
                                                              }

                                                              });
        // 设置redisTask的属性和请求
        protocol::RedisRequest *req = redisTask->get_req();
        // 是一个写命令
    //req->set_request("SET",{"x","54"});

    // 是一个读命令
    req->set_request("GET",{"x"});
    // 将任务派给框架,由g框架异步调用
        redisTask->start();
        gWaitGroup.wait(); // 等待直到计数器减一f
        return 0;
}

  • 读取复杂数据
    在这里插入图片描述
if (value.is_string())
{
    cout << "value is a string , value = " << value.string_value() << endl;
}
else if (value.is_array())
{
    for (size_t i = 0; i < value.arr_size(); ++i)
    {
        cout << "value is arr,i = " << i << ",arr[i] = " << value.arr_at(i).string_value() << endl;
    }
}

在这里插入图片描述

注意:框架的执行单位是序列

串行任务(序列 serial)

在这里插入图片描述


#include "unixHeader.h"
#include <workflow/RedisMessage.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#define RETRY_MAX 2
struct tutorial_task_data
{
    std::string url;
    std::string key;
};
void redis_callback(WFRedisTask *task)
{
    protocol::RedisRequest *req = task->get_req();
    protocol::RedisResponse *resp = task->get_resp();
    int state = task->get_state();
    int error = task->get_error();
    protocol::RedisValue val;
    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:
        resp->get_result(val);
        if (val.is_error())
        {
            fprintf(stderr, "Error reply. Need a password?\n");
            state = WFT_STATE_TASK_ERROR;
        }
        break;
    }
    if (state != WFT_STATE_SUCCESS)
    {
        fprintf(stderr, "Failed. Press Ctrl-C to exit.\n");
        return;
    }
    std::string cmd;
    整个程序的流程执行如下:
    req->get_command(cmd);
    if (cmd == "SET")
    {
        tutorial_task_data *data = (tutorial_task_data *)task->user_data;
        WFRedisTask *next = WFTaskFactory::create_redis_task(data->url,
                                                             RETRY_MAX,
                                                             redis_callback);
        next->get_req()->set_request("GET", {data->key});
        /* Push next task(GET task) to current series. */
        series_of(task)->push_back(next);
        fprintf(stderr, "Redis SET request success. Trying to GET...\n");
    }
    else /* if (cmd == "GET") */
    {
        if (val.is_string())
        {
            fprintf(stderr, "Redis GET success. value = %s\n",
                    val.string_value().c_str());
        }
        else
        {
            fprintf(stderr, "Error: Not a string value. \n");
        }
        fprintf(stderr, "Finished. Press Ctrl-C to exit.\n");
    }
}
static WFFacilities::WaitGroup wait_group(1);
void sig_handler(int signo)
{
    wait_group.done();
}
int main(int argc, char *argv[])
{
    signal(SIGINT, sig_handler);
    struct tutorial_task_data data;
    data.url = "redis://127.0.0.1:6379";
    data.key = "key1";
    WFRedisTask *task = WFTaskFactory::create_redis_task(data.url, RETRY_MAX,
                                                         redis_callback);
    protocol::RedisRequest *req = task->get_req();
    req->set_request("SET", {data.key, "value2"});
    /* task->user_data is a public (void *), can store anything. */
    task->user_data = &data;
    task->start();
    wait_group.wait();
    return 0;
}

在这里插入图片描述

f

#include <54func.h>
#include<iostream>
#include<string>
#include <workflow/WFFacilities.h>
#include<workflow/HttpMessage.h>
#include<workflow/HttpUtil.h>

using std::cout;
using std::endl;
using std::string;

static WFFacilities::WaitGroup gWaitGroup(1);  // 计数器

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done(); //计数器减一
}
// 阻塞主线程,直到按住Ctrl+C
int main()
{
    signal(SIGINT,handler);
    cout<<"1"<<endl;
    // 利用工厂函数创建一个任务
    WFRedisTask *redisTask = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,
                                                              [](WFRedisTask *redisTask){
                                                             sleep(1);
                                                             cout<<"Task 1 sleep over"<<endl;
                                                              protocol::RedisRequest *req = redisTask->get_req();
                                                              protocol::RedisResponse *resp = redisTask->get_resp();
                                                                                                                          protocol::RedisValue value ; // 获取redis返回的结果
                                                              int state  = redisTask->get_state();
                                                              int error = redisTask->get_error();
                                                              // error只能处理网络连接和系统错误,语法错误只能通过返回结果查看oo
                                                                                                                          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:
                                                                                                                                        resp->get_result(value);  // 语法错误只能通过返回结果进行查看
                                                                                                                                        if(value.is_error())
                                                                                                                                        {
                                                                                                                                                cout<<"语法错误"<<endl;
                                                                                                                                                state = WFT_STATE_TASK_ERROR; // 任务层面的错误
                                                                                                                                        }
                                                                                                                                        break;
                                                                                                                          }
                                                                                                                          if (state != WFT_STATE_SUCCESS)
                                                                                                                          {
                                                                                                                                        fprintf(stderr, "Failed. Press Ctrl-C to exit.\n");
                                                                                                                                        return;
                                                                                                                          }
                                                              if(value.is_string())
                                                              {
                                                                  cout<<"value is a string , value = "<<value.string_value()<<endl;
                                                              }
                                                              else if(value.is_array())
                                                              {
                                                                  for(size_t i = 0;i<value.arr_size();++i)
                                                                  {
                                                                      cout<<"value is arr,i = "<<i<<",arr[i] = "<<value.arr_at(i).string_value()<<endl;
                                                                  }
                                                              }

                                                              });
        // 设置redisTask的属性和请求
        protocol::RedisRequest *req1 = redisTask->get_req();
        // 是一个写命令
    req1->set_request("SET",{"54","ABC"});





    WFRedisTask *redisTask2 = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,
                                                              [](WFRedisTask *redisTask){
                                                              protocol::RedisRequest *req = redisTask->get_req();
                                                              protocol::RedisResponse *resp = redisTask->get_resp();
                                                                                                                          protocol::RedisValue value ; // 获取redis返回的结果
                                                              int state  = redisTask->get_state();
                                                              int error = redisTask->get_error();
                                                              // error只能处理网络连接和系统错误,语法错误只能通过返回结果查看oo
                                                                                                                          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:
                                                                                                                                        resp->get_result(value);  // 语法错误只能通过返回结果进行查看
                                                                                                                                        if(value.is_error())
                                                                                                                                        {
                                                                                                                                                cout<<"语法错误"<<endl;
                                                                                                                                                state = WFT_STATE_TASK_ERROR; // 任务层面的错误
                                                                                                                                        }
                                                                                                                                        break;
                                                                                                                          }
                                                                                                                          if (state != WFT_STATE_SUCCESS)
                                                                                                                          {
                                                                                                                                        fprintf(stderr, "Failed. Press Ctrl-C to exit.\n");
                                                                                                                                        return;
                                                                                                                          }
                                                              if(value.is_string())
                                                              {
                                                                  cout<<"value is a string , value = "<<value.string_value()<<endl;
                                                              }
                                                              else if(value.is_array())
                                                              {
                                                                  for(size_t i = 0;i<value.arr_size();++i)
                                                                  {
                                                                      cout<<"value is arr,i = "<<i<<",arr[i] = "<<value.arr_at(i).string_value()<<endl;
                                                                  }
                                                              }

                                                              });
        // 设置redisTask的属性和请求
        protocol::RedisRequest *req2 = redisTask2->get_req();
        // 是一个写命令
    req2->set_request("GET",{"54"});

    //  创建一个x序列
    SeriesWork *series = Workflow::create_series_work(redisTask,nullptr);
    series->push_back(redisTask2);
    series->start();
    // 将任务派给框架,由g框架异步调用
        gWaitGroup.wait(); // 等待直到计数器减一f
        return 0;
}


在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

回调任务中创建任务

在这里插入图片描述
在这里插入图片描述

在序列执行过程中增加任务

在这里插入图片描述

在这里插入图片描述

在序列的任务之间共享数据

在这里插入图片描述


#include <54func.h>
#include <iostream>
#include <string>
#include <workflow/WFFacilities.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>

using std::cout;
using std::endl;
using std::string;

struct SeriesContext
{
    int i;
    string str;
};
static WFFacilities::WaitGroup gWaitGroup(1); // 计数器

void handler(int signum)
{
    printf("signum = %d\n", signum);
    gWaitGroup.done(); // 计数器减一
}
// 阻塞主线程,直到按住Ctrl+C
int main()
{
    signal(SIGINT, handler);
    cout << "1" << endl;
    // 利用工厂函数创建一个任务
    WFRedisTask *redisTask = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379", 0,
                                                              [](WFRedisTask *redisTask)
                                                              {
                                                                  sleep(1);
                                                                  cout << "Task 1 sleep over" << endl;
                                                                  protocol::RedisRequest *req = redisTask->get_req();
                                                                  protocol::RedisResponse *resp = redisTask->get_resp();
                                                                  protocol::RedisValue value; // 获取redis返回的结果
                                                                  resp->get_result(value);

                                                                  SeriesContext *pContext = new SeriesContext;
                                                                  series_of(redisTask)->set_context(pContext);
                                                                  pContext->i = 1;
                                                                  pContext->str = "hello";

                                                                  if (value.is_string() && value.string_value() == "OK")
                                                                  {
                                                                      cout << "Task 1 value is a string , value = " << value.string_value() << endl;
                                                                      cout << "Task 2 is create " << endl;
                                                                      WFRedisTask *redisTask2 = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379", 0,
                                                                                                                                 [](WFRedisTask *redisTask)
                                                                                                                                 {
                                                                                                                                     protocol::RedisRequest *req = redisTask->get_req();
                                                                                                                                     protocol::RedisResponse *resp = redisTask->get_resp();
                                                                                                                                     protocol::RedisValue value; // 获取redis返回的结果
                                                                                                                                     resp->get_result(value);
                                                                                                                                     SeriesContext *pContext = (SeriesContext *)(series_of(redisTask)->get_context());
                                                                                                                                     // 但是何时释放pContext,可以放在序列中的回调函数中进行释放

                                                                                                                                     if (value.is_string())
                                                                                                                                     {
                                                                                                                                         cout << "Task 2 " << value.string_value() << endl;
                                                                                                                                         cout << "Task 2 i = " << pContext->i << "  str=" << pContext->str << endl;
                                                                                                                                     }
                                                                                                                                 });
                                                                      protocol::RedisRequest *req2 = redisTask2->get_req();
                                                                      req2->set_request("GET", {"54"});
                                                                      // redisTask2->start();
                                                                      series_of(redisTask)->push_back(redisTask2); // 找到当前所在的序列,并将Task2加入其中
                                                                  }
                                                                  else
                                                                  {
                                                                      cout << "Task 2 is not create" << endl;
                                                                  }
                                                                  // 给序列添加回调函数,释放共享的数据
                                                                  series_of(redisTask)->set_callback(
                                                                      [](const SeriesWork *series)
                                                                      {
                                                                          cout << "Series CallBack" << endl;
                                                                          SeriesContext *pContext = (SeriesContext *)series->get_context();
                                                                          delete pContext;
                                                                      });
                                                              });
    // 在redisTask1回调的过程中创建u一个x新任务
    // 设置redisTask的属性和请求
    protocol::RedisRequest *req1 = redisTask->get_req();
    // 是一个写命令
    req1->set_request("SET", {"54", "A"});
    redisTask->start();

    // 将任务派给框架,由g框架异步调用
    gWaitGroup.wait(); // 等待直到计数器减一f
    return 0;
}

在这里插入图片描述

在这里插入图片描述
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7c5561df77894646abc5a7b091fb59b3.png

作业

在这里插入图片描述
在这里插入图片描述


#include<54func.h>
#include<iostream>
#include<string>
#include<workflow/WFFacilities.h>
#include<workflow/HttpMessage.h>
#include<workflow/HttpUtil.h>

using std::cout;
using std::string;
using std::endl;


static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done();
}

class HomeWork
{
public:
    void init_query()
    {

        WFRedisTask *redisTask = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,
                                                                  std::bind(&HomeWork::on_redis_return,this,std::placeholders::_1));
        redisTask->get_req()->set_request("GET",{"x1"});
        redisTask->start();
    }

    void on_redis_return(WFRedisTask *redisTask)
    {

        protocol::RedisResponse *resp = redisTask->get_resp();
        protocol::RedisValue value ; // 获取redis返回的结果
        resp->get_result(value);
        if(value.is_ok() && value.string_value() == "100")
        {
            cout<<"finished"<<endl;
            return;
        }
        else
        {
            cout<<"current value is "<<value.string_value()<<endl;
            sleep(1);
            WFRedisTask *nextRedisTask =
            WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,
                        std::bind(&HomeWork::on_redis_return,this,std::placeholders::_1));
            nextRedisTask->get_req()->set_request("GET",{value.string_value()});
            series_of(redisTask)->push_back(nextRedisTask);

        }
    }
};

int main()
{
    signal(SIGINT,handler);
    HomeWork homework;
    homework.init_query();
    gWaitGroup.wait();
    return 0;
}

在这里插入图片描述

在这里插入图片描述




#include<54func.h>
#include<iostream>
#include<string>
#include<workflow/WFFacilities.h>
#include<workflow/HttpMessage.h>
#include<workflow/HttpUtil.h>

using std::cout;
using std::string;
using std::endl;


static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
    printf("signum = %d\n",signum);
    gWaitGroup.done();
}

class HomeWork
{
public:
    void init_query()
    {
        WFHttpTask *httpTask =
            WFTaskFactory::create_http_task("http://www.taobao.com",10,0,
                            std::bind(&HomeWork::on_http_response,this,std::placeholders::_1));
        httpTask->start();
    }

    void on_http_response(WFHttpTask *httpTask)
    {
        protocol::HttpResponse *resp = httpTask->get_resp();
        const void * body;
        size_t size;
        resp->get_parsed_body(&body,&size);
        string value((char*)body,size);
        WFRedisTask *redisTask =
            WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,
            std::bind(&HomeWork::on_redis_return,this,std::placeholders::_1));
        redisTask->get_req()->set_request("SET",{"www.taobao.com",value});
        series_of(httpTask)->push_back(redisTask);
    }

    void on_redis_return(WFRedisTask *redisTask)
    {
        protocol::RedisResponse *resp = redisTask->get_resp();
        protocol::RedisValue value;
        resp->get_result(value);
        if(value.is_ok())
        {
            cout<<"value is "<<value.string_value()<<endl;
        }
    }
};

int main()
{
    signal(SIGINT,handler);
    HomeWork homework;
    homework.init_query();
    gWaitGroup.wait();
    return 0;
}

并行任务(paralell_work)

在这里插入图片描述

使用并行任务的基本流程

在这里插入图片描述
在这里插入图片描述

一个复杂的使用并行任务的例子(并联之后串行)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


#include<iostream>
#include <vector>
#include <string>
#include <workflow/Workflow.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
using namespace std;
static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
        printf("signum = %d\n",signum);
    gWaitGroup.done();
}

void httpCallback(WFHttpTask *httpTask)
{
    cout<<"http Callback"<<endl;
    protocol::HttpResponse *resp = httpTask->get_resp();
    cout<<resp->get_http_version()<<" "
        <<resp->get_status_code()<<" "
        <<resp->get_reason_phrase()<<endl;
    const void * body;
    size_t size;
    resp->get_parsed_body(&body,&size);
    cout<<"szie = "<<size<<endl;
}


int main()
{
    vector<string> vec{
        "http://www.qq.com",
        "http://www.baidu.com",
        "http://www.taobao.com"
    };

    // 创建一个并行任务
    ParallelWork *parallel = Workflow::create_parallel_work(nullptr);
    for(int i =0;i<3;i++)
    {
        // 创建一个简单的http任务
        WFHttpTask *httpTask = WFTaskFactory::create_http_task(vec[i],10,0,httpCallback);
        // 创建序列
        SeriesWork *series = Workflow::create_series_work(httpTask,nullptr);
        // v把序列加入到并行任务中
        parallel->add_series(series);
    }
    parallel->start(); // 启动parrel
    gWaitGroup.wait();
}

在这里插入图片描述

#include<iostream>
#include <vector>
#include <string>
#include <workflow/Workflow.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
using namespace std;

struct SeriesContext{
    string url;
    size_t size;
};

static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
        printf("signum = %d\n",signum);
    gWaitGroup.done();
}

void httpCallback(WFHttpTask *httpTask)
{
    cout<<"http Callback"<<endl;
    protocol::HttpResponse *resp = httpTask->get_resp();
    cout<<resp->get_http_version()<<" "
        <<resp->get_status_code()<<" "
        <<resp->get_reason_phrase()<<endl;
    const void * body;
    size_t size;
    resp->get_parsed_body(&body,&size);
    cout<<"size = "<<size<<endl;

    // 回调执行过程中也会写入context
    SeriesContext *context = (SeriesContext *)series_of(httpTask)->get_context();
    context->size = size;
}

void parallelCallback(const ParallelWork *parallel)
{
    cout<<"parallel work"<<endl;
    for(size_t i = 0;i<parallel->size();++i)
    {
        // size()  获取序列的个数
        SeriesContext *context = (SeriesContext *)parallel->series_at(i)->get_context();
        // series_at获取某个序列
        cout<<"url = "<<context->url<<"size = "<<context->size<<endl;
        delete context;
    }
}
int main()
{
    vector<string> vec{
        "http://www.qq.com",
        "http://www.baidu.com",
        "http://www.taobao.com"
    };

    // 创建一个并行任务
    ParallelWork *parallel = Workflow::create_parallel_work(parallelCallback);
    for(int i =0;i<3;i++)
    {
        // 创建一个简单的http任务
        WFHttpTask *httpTask = WFTaskFactory::create_http_task(vec[i],10,0,httpCallback);
        // 创建序列
        SeriesWork *series = Workflow::create_series_work(httpTask,nullptr);
        // 在创建序列之后,申请Context
        SeriesContext *context = new SeriesContext();
        series->set_context(context);
        context->url = vec[i];
        // v把序列加入到并行任务中
        parallel->add_series(series);
    }
    parallel->start(); // 启动parrel
    gWaitGroup.wait();
}

在这里插入图片描述
在这里插入图片描述

)

在这里插入图片描述

给所有序列都添加上回调函数

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Redis处理接口幂等性的两种方案

下游传递唯一请求编号

在这里插入图片描述

防重Token令牌

在这里插入图片描述
在这里插入图片描述

使用Workflow作为HTTP服务端

在这里插入图片描述

在这里插入图片描述

process函数对象

  • 一有请求就去调用process函数,序列是自动创建的
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 简单的使用

#include <54func.h>
#include<iostream>
#include <vector>
#include <string>
#include <workflow/Workflow.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

using namespace std;
using std::endl;
using std::cout;
using std::string;
using std::vector;

static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
        printf("signum = %d\n",signum);
    gWaitGroup.done();
}

void process(WFHttpTask *serverTask)
{
    cout<<"Process is called"<<endl;
}

int main()
{
   signal(SIGINT,handler);
   WFHttpServer server(process);
   server.start(1234); // listen 1234端口
   gWaitGroup.wait();
}

在这里插入图片描述

  • 第一个服务端

#include <54func.h>
#include<iostream>
#include <vector>
#include <string>
#include <workflow/Workflow.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

using namespace std;
using std::endl;
using std::cout;
using std::string;
using std::vector;

static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
        printf("signum = %d\n",signum);
    gWaitGroup.done();
}

void process(WFHttpTask *serverTask)
{
    cout<<"Process is called"<<endl;
    // 修改响应
    protocol::HttpResponse *resp = serverTask->get_resp();
    resp->set_http_version("HTTP/1.1");
    resp->set_status_code("200");
    resp->set_reason_phrase("ok");
    resp->set_header_pair("Content-type","text/html");
    // workflow框架会自动加入s首部字段 connection keep-aline
    resp->append_output_body("<html>Hello</html>");
}

int main()
{
   signal(SIGINT,handler);
   WFHttpServer server(process);
   server.start(1234); // listen 1234端口
   gWaitGroup.wait();
}

在这里插入图片描述

  • 响应放到回调函数中
#include <54func.h>
#include<iostream>
#include <vector>
#include <string>
#include <workflow/Workflow.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

using namespace std;
using std::endl;
using std::cout;
using std::string;
using std::vector;

static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
        printf("signum = %d\n",signum);
    gWaitGroup.done();
}

void process(WFHttpTask *serverTask)
{
    cout<<"Process is called"<<endl;

    serverTask->set_callback(
                             [](WFHttpTask * serverTask)
                             {
                             cout<<"Callback is called"<<endl;
                             protocol::HttpResponse *resp = serverTask->get_resp();
                             resp->set_http_version("HTTP/1.1");
                             resp->set_status_code("200");
                             resp->set_reason_phrase("ok");
                             resp->set_header_pair("Content-type","text/html");
                             // workflow框架会自动加入s首部字段 connection keep-aline
                             resp->append_output_body("<html>Hello</html>");
                             }
                            );
    // 修改响应
}

int main()
{
   signal(SIGINT,handler);
   WFHttpServer server(process);
   server.start(1234); // listen 1234端口
   gWaitGroup.wait();
}

在这里插入图片描述

在服务端任务序列中添加任务

登录业务

在这里插入图片描述
在这里插入图片描述

  • 执行顺序的确定

#include <54func.h>
#include<iostream>
#include <vector>
#include <string>
#include <workflow/Workflow.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

using namespace std;
using std::endl;
using std::cout;
using std::string;
using std::vector;

static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
        printf("signum = %d\n",signum);
    gWaitGroup.done();
}

void redisCallback(WFRedisTask *serverTask)
{
    cout<<"redisCallback is called"<<endl;
}
void serverTaskCallback(WFHttpTask *serverTask)
{
    cout<<"serverTaskCallback is called"<<endl;
}

void process(WFHttpTask *serverTask)
{
    cout<<"Process is called"<<endl;
    // 修改响应

    // 获取r用户名和密码
    protocol::HttpRequest *req = serverTask->get_req();
    string uri = req->get_request_uri();
    string nameKV = uri.substr(0,uri.find("&"));
    string passwdKV = uri.substr(uri.find("&")+1);

    string name = nameKV.substr(nameKV.find("=")+1);
    string passwd = passwdKV.substr(passwdKV.find("=")+1);
    cout<<"name = "<<name<<"  passwd="<<passwd<<endl;

    // 创建Redistask
    WFRedisTask *redisTask=
        WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,redisCallback);
    redisTask->get_req()->set_request("hget",{"54user",name});// 这个任务需要process之后执行
    series_of(serverTask)->push_back(redisTask);
    serverTask->set_callback(serverTaskCallback);
    cout<<"process is returned"<<endl;
}

int main()
{
   signal(SIGINT,handler);
   WFHttpServer server(process);
   server.start(1234); // listen 1234端口
   gWaitGroup.wait();
}

在这里插入图片描述


#include <54func.h>
#include<iostream>
#include <vector>
#include <string>
#include <workflow/Workflow.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

using namespace std;
using std::endl;
using std::cout;
using std::string;
using std::vector;

static WFFacilities::WaitGroup gWaitGroup(1);

struct  SeriesContext
{
    string password;
    protocol::HttpResponse *resp;
};
void handler(int signum)
{
        printf("signum = %d\n",signum);
    gWaitGroup.done();
}

void redisCallback(WFRedisTask *redisTask)
{
    cout<<"redisCallback is called"<<endl;
    protocol::RedisResponse *resp = redisTask->get_resp();
    protocol::RedisValue value;
    resp->get_result(value);

    // 提取共享的数据
    SeriesContext *context = (SeriesContext*)series_of(redisTask)->get_context();
    if(value.string_value() == context->password)
    {
        context->resp->append_output_body("login success");
    }
    else
    {
        context->resp->append_output_body("login failed");
    }
    delete context;
}
void serverTaskCallback(WFHttpTask *serverTask)
{
    cout<<"serverTaskCallback is called"<<endl;
}

void process(WFHttpTask *serverTask)
{
    cout<<"Process is called"<<endl;
    // 修改响应

    // 获取r用户名和密码
    protocol::HttpRequest *req = serverTask->get_req();
    string uri = req->get_request_uri();
    string nameKV = uri.substr(0,uri.find("&"));
    string passwdKV = uri.substr(uri.find("&")+1);

    string name = nameKV.substr(nameKV.find("=")+1);
    string passwd = passwdKV.substr(passwdKV.find("=")+1);
    cout<<"name = "<<name<<"  passwd="<<passwd<<endl;

    // 设置要共享的数据
    SeriesContext *context = new SeriesContext;
    context->password = passwd;
    context->resp = serverTask->get_resp();
    series_of(serverTask)->set_context(context);

    // 创建Redistask
    WFRedisTask *redisTask=
        WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,redisCallback);
    redisTask->get_req()->set_request("hget",{"54user",name});// 这个任务需要process之后执行
    series_of(serverTask)->push_back(redisTask);
    serverTask->set_callback(serverTaskCallback);
    cout<<"process is returned"<<endl;
}

int main()
{
   signal(SIGINT,handler);
   WFHttpServer server(process);
   server.start(1234); // listen 1234端口
   gWaitGroup.wait();
}

在这里插入图片描述
在这里插入图片描述

部署静态资源

pread任务和pwrite任务

在这里插入图片描述

#include <54func.h>
#include<iostream>
#include <vector>
#include <string>
#include <workflow/Workflow.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

using namespace std;
using std::endl;
using std::cout;
using std::string;
using std::vector;

struct SeriesContext
{
    protocol::HttpResponse *resp;
    char buf[4096];
};

static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
        printf("signum = %d\n",signum);
    gWaitGroup.done();
}

void fileIOCallback(WFFileIOTask *preadTask)
{
    cout<<"fileIOCallback is called"<<endl;
    SeriesContext *context = (SeriesContext*)series_of(preadTask)->get_context();
    cout<<"buf = "<<context->buf<<endl;
    context->resp->append_output_body(context->buf,strlen(context->buf));


}

void process(WFHttpTask *serverTask)
{
    cout<<"Process is called"<<endl;
    // 修改响应
    protocol::HttpResponse *resp = serverTask->get_resp();
    resp->set_http_version("HTTP/1.1");
    resp->set_status_code("200");
    resp->set_reason_phrase("ok");
    resp->set_header_pair("Content-type","text/html");
    // workflow框架会自动加入s首部字段 connection keep-aline
    resp->append_output_body("<html>Hello</html>");

    protocol::HttpRequest *req = serverTask->get_req();
    string method = req->get_method();
    if(method == "GET")
    {
        int fd = open("postform.html",O_RDONLY);
        SeriesContext *context = new SeriesContext();
        context->resp = resp;
        series_of(serverTask)->set_context(context);
        WFFileIOTask *preadTask = WFTaskFactory::create_pread_task(fd,context->buf,4096,0,fileIOCallback);
        series_of(serverTask)->push_back(preadTask);
    }
    else
    {
        resp->append_output_body("<html>Yes</html>");
    }


}

int main()
{
   signal(SIGINT,handler);
   WFHttpServer server(process);
   server.start(1234); // listen 1234端口
   gWaitGroup.wait();
}
wfrest库
  • 目的是简化workflow的使用
  • 按照这样写,uri路由匹配太多了
    在这里插入图片描述

在这里插入图片描述

项目实战:分块上传功能实现

安装wfrest

在这里插入图片描述

分块上传功能的实现方案

在这里插入图片描述

在这里插入图片描述

接口1:POST /file/mupload/init

在这里插入图片描述

上传ID生成

在这里插入图片描述

分块信息处理

在这里插入图片描述
在这里插入图片描述

接口2:POST /file/mupload/uppart

在这里插入图片描述
在这里插入图片描述

接口3:/file/mupload/complete

在这里插入图片描述
在这里插入图片描述

#include <signal.h>
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>
#include <workflow/HttpUtil.h>
#include <wfrest/json.hpp>
#include "UnixHeader.h"
using Json = nlohmann::json;
static WFFacilities::WaitGroup waitGroup(1);
void sighandler(int signum)
{
    printf("finish 1 work!\n");
    waitGroup.done();
}
void process(WFHttpTask *serverTask)
{
    // http://192.168.118.128:1234/file/mupload/init
    // http://192.168.118.128:1234/file/mupload/uppart?uploadID=liao1122&chkidx=2
    // http://192.168.118.128:1234/file/mupload/complete?uploadID=liao1122
    auto req = serverTask->get_req();
    auto resp = serverTask->get_resp();
    std::string uri = req->get_request_uri();
    std::string path = uri.substr(0, uri.find("?"));
    std::string query = uri.substr(uri.find("?") + 1);
    std::string method = req->get_method();
    if (path == "/file/mupload/init" && method == "POST")
    {
        // 1 解析请求报文
        const void *body;
        size_t size;
        req->get_parsed_body(&body, &size);
        // 2 从字符串解析成json
        Json fileInfo = Json::parse(static_cast<const char *>(body));
        std::string filename = fileInfo["filename"];
        int filesize = fileInfo["filesize"];
        std::string filehash = fileInfo["filehash"];
        // fprintf(stderr,"%s %s %d\n", filename.c_str(), filehash.c_str(), filesize);
        //  3 初始化分块操作
        //  生成uploadID
        std::string uploadID = "liao";
        time_t now = time(NULL);
        struct tm *ptm = localtime(&now);
        char timeStamp[30] = {0};
        sprintf(timeStamp, "%02d%02d%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
        uploadID = uploadID + timeStamp;
        // fprintf(stderr,"%s\n", uploadID.c_str());
        //  生成分块信息
        int chunkcount;
        int chunksize = 1024 * 1024;
        if (filesize % chunksize != 0)
        {
            chunkcount = filesize / chunksize + 1;
        }
        else
        {
            chunkcount = filesize / chunksize;
        }
        // fprintf(stderr,"chunksize = %d, chunkcount = %d\n", chunksize, chunkcount);
        //  初始化redis
        //  HSET uploadID chunkcount 6
        //  HSET uploadID filehash xxx
        //  HSET uploadID filesize xxx
        std::vector<std::vector<std::string>> argsVec = {
            {uploadID, "chunkcount", std::to_string(chunkcount)},
            {uploadID, "filehash", filehash},
            {uploadID, "filesize", std::to_string(filesize)}};
        for (int i = 0; i < 3; ++i)
        {
            auto redisTask = WFTaskFactory::create_redis_task("redis://localhost", 0, nullptr);
            redisTask->get_req()->set_request("HSET", argsVec[i]);
            redisTask->start();
        }
        // 生成响应给客户端
        Json uppartInfo;
        uppartInfo["status"] = "OK";
        uppartInfo["uploadID"] = uploadID;
        uppartInfo["chunkcount"] = chunkcount;
        uppartInfo["filesize"] = filesize;
        uppartInfo["chunksize"] = chunksize;
        uppartInfo["filehash"] = filehash;
        resp->append_output_body(uppartInfo.dump());
    }
    else if (path == "/file/mupload/uppart" && method == "POST")
    {
        // fprintf(stderr,"uppart\n");
        //  解析uri的查询参数,提取出uploadID和chkidx
        //  query = "uploadID=liao101335&chkidx=2"
        std::string uploadIDKV = query.substr(0, query.find("&"));
        std::string uploadID = uploadIDKV.substr(uploadIDKV.find("=") + 1);
        std::string chkidxKV = query.substr(query.find("&") + 1);
        std::string chkidx = chkidxKV.substr(chkidxKV.find("=") + 1);
        // 保存单个分片 ./filehash/1 filehash需要从redis当中获取 HGET uploadID filehash
        auto redisTaskHGET = WFTaskFactory::create_redis_task("redis://localhost", 0, [chkidx, req](WFRedisTask *redisTaskHGET)
                                                              {
            protocol::RedisValue value;
            redisTaskHGET->get_resp()->get_result(value);
            std::string filehash = value.string_value();
            mkdir(filehash.c_str(),0777);
            std::string filepath = filehash + "/" + chkidx;
            // 文件IO任务
            int fd = open(filepath.c_str(),O_RDWR|O_CREAT,0666);
            const void *body;
            size_t size;
            req->get_parsed_body(&body,&size);
            write(fd,body,size);
            close(fd); });
        redisTaskHGET->get_req()->set_request("HGET", {uploadID, "filehash"});
        series_of(serverTask)->push_back(redisTaskHGET);
        // 记录下载进度 HSET uploadID chkidx 1
        auto redisTaskHSET = WFTaskFactory::create_redis_task("redis://localhost", 0, nullptr);
        redisTaskHSET->get_req()->set_request("HSET", {uploadID, "chkidx_" + chkidx, "1"});
        series_of(serverTask)->push_back(redisTaskHSET);

        // 设置响应的内容
        resp->append_output_body("OK");
    }
    else if (path == "/file/mupload/complete" && method == "POST")
    {
        // fprintf(stderr,"complete\n");
        // 解析请求,提取出uploadID
        std::string uploadID = query.substr(query.find("=") + 1);
        // 查询上传进度
        //  HGETALL uploadID
        //  chunkcount键所对应的值-->下载的总进度
        //  前缀为chkidx_的键的数量-->下载的当前进度
        auto redisTask = WFTaskFactory::create_redis_task("redis://localhost", 0, [resp](WFRedisTask *redisTask)
                                                          {
            protocol::RedisValue value;
            redisTask->get_resp()->get_result(value);
            int chunkcount;
            int chunknow = 0;
            for(int i = 0; i < value.arr_size(); i+=2){
                std::string key = value.arr_at(i).string_value();
                std::string val = value.arr_at(i+1).string_value();
                if(key == "chunkcount"){
                    chunkcount = std::stoi(val);
                }
                else if(key.substr(0,7) == "chkidx_"){
                    ++chunknow;
                }
            }
            //fprintf(stderr,"chunkcount = %d, chunknow = %d\n", chunkcount, chunknow);
            if(chunkcount == chunknow){
                //分块合并操作
                resp->append_output_body("SUCCESS");
            }
            else{
                resp->append_output_body("FAIL");
            } });
        redisTask->get_req()->set_request("HGETALL", {uploadID});
        series_of(serverTask)->push_back(redisTask);
    }
}
int main()
{
    signal(SIGINT, sighandler);
    WFHttpServer server(process);
    if (server.start(1234) == 0)
    {
        waitGroup.wait();
        server.stop();
    }
    else
    {
        perror("server start error!\n");
        exit(-1);
    }
    return 0;
}

MySQL任务

workflow去操作表的时候,表的名字前面一定要加 数据库名.
在这里插入图片描述

  • 注意是在做客户端

在这里插入图片描述

#include <54func.h>
#include <iostream>
#include <vector>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#include <workflow/MySQLMessage.h>
#include <workflow/MySQLResult.h>
#include <workflow/MySQLUtil.h>
static WFFacilities::WaitGroup waitGroup(1);
void sigHandler(int num)
{
    waitGroup.done();
    printf("waitGroup is done\n");
}
void mysqlCallback(WFMySQLTask *mysqlTask)
{
    // step 1 检查连接的状态
    if (mysqlTask->get_state() != WFT_STATE_SUCCESS)
    {
        std::cerr << "error msg :" << WFGlobal::get_error_string(mysqlTask->get_state(), mysqlTask->get_error());
        return;
    }
    protocol::MySQLResponse *resp = mysqlTask->get_resp();
    protocol::MySQLResultCursor cursor(mysqlTask->get_resp());
    // step 2 检查mysql任务的状态
    if (resp->get_packet_type() == MYSQL_PACKET_ERROR)
    {
        std::cerr << "ERROR, error code = " << resp->get_error_code()
                  << " msg = " << resp->get_error_msg();
        return;
    }
    do
    { // step 3 遍历结果集合
      // step 4 判断指令的类型是 读 select 写 update insert delete from alter
        if (cursor.get_cursor_status() == MYSQL_STATUS_OK)
        {
            // 说明是写操作
            std::cerr << "OK, " << cursor.get_affected_rows() << " rows affected."
                      << cursor.get_warnings() << " warnings. insert_id = " << cursor.get_insert_id() << ".\n";
        }
        else if (cursor.get_cursor_status() == MYSQL_STATUS_GET_RESULT)
        {
            // 说明sql语句是读操作
            std::cerr << "field count = " << cursor.get_field_count()
                      << " rows count = " << cursor.get_rows_count() << "\n";
            // 找到所有域的信息
            const protocol::MySQLField *const *fields = cursor.fetch_fields();
            for (int i = 0; i < cursor.get_field_count(); ++i)
            {
                std::cerr << "database = " << fields[i]->get_db()
                          << " table = " << fields[i]->get_table()
                          << " fieldname = " << fields[i]->get_name()
                          << " fieldtype = " << datatype2str(fields[i]->get_data_type())
                          << "\n";
            }
            // 取出表格当中的所有内容
            std::vector<std::vector<protocol::MySQLCell>> rows;
            cursor.fetch_all(rows);
            for (unsigned int j = 0; j < rows.size(); ++j)
            {
                for (unsigned int i = 0; i < rows[j].size(); ++i)
                {
                    if (rows[j][i].is_int())
                    {
                        std::cerr << rows[j][i].as_int() << " ";
                    }
                    else if (rows[j][i].is_string())
                    {
                        std::cerr << rows[j][i].as_string() << " ";
                    }
                    else if (rows[j][i].is_datetime())
                    {
                        std::cerr << rows[j][i].as_datetime() << " ";
                    }
                }
                std::cerr << "\n";
            }
        }
    } while (cursor.next_result_set()); // 多个sql指令合在一起的情况
    //cursor.next_result_set(); // 当执行多个sql语句时
}
int main()
{
    signal(SIGINT, sigHandler);
    WFMySQLTask *mysqlTask =
        WFTaskFactory::create_mysql_task("mysql://root:123@127.0.0.1:3306", 0, mysqlCallback);
    // std::string sql = "update cloudisk.tbl_user set email_validated = 1 where
    // std::string sql = "show databases;";
    //std::string sql = "select * from cloudisk.tbl_user_token;";
    //std::string sql = "INSERT INTO cloudisk.tbl_user_token  VALUES(1, 'liao', 'abcdef');";
    // workflow去操作表的时候,表的名字前面一定要加 数据库名.

    std::string sql = "select * from cloudisk.tbl_user_token;";
    sql += "INSERT INTO cloudisk.tbl_user_token  VALUES(3, 'liao3', 'abcdef');";
    auto req = mysqlTask->get_req();
    req->set_query(sql);
    mysqlTask->start();
    waitGroup.wait();
}

Mysql可以执行多个语句,redis一次只能执行一个任务

定时任务

在这里插入图片描述

#include <54func.h>
#include <iostream>
#include <map>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#include <wfrest/HttpServer.h>
static WFFacilities::WaitGroup waitGroup(1);
void sigHandler(int num)
{
    waitGroup.done();
    printf("waitGroup is done\n");
}
void timerCallback(WFTimerTask *timerTask)
{
    std::cerr << "timer callback " << time(NULL) << std::endl;
    WFTimerTask *nextTask =
        WFTaskFactory::create_timer_task(5000000, timerCallback);
    series_of(timerTask)->push_back(nextTask);
}
int main()
{
    signal(SIGINT, sigHandler);
    WFTimerTask *timerTask =
        WFTaskFactory::create_timer_task(5000000, timerCallback);
    timerTask->start();
    std::cerr << "timer start " << time(NULL) << std::endl;
    waitGroup.wait();
    return 0;
}

在这里插入图片描述

文件IO任务

文件IO任务

在这里插入图片描述

示例:静态资源服务器

在这里插入图片描述

pread任务和pwrite任务

在这里插入图片描述

#include <54func.h>
#include<iostream>
#include <vector>
#include <string>
#include <workflow/Workflow.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

using namespace std;
using std::endl;
using std::cout;
using std::string;
using std::vector;

struct SeriesContext
{
    protocol::HttpResponse *resp;
    char buf[4096];
};

static WFFacilities::WaitGroup gWaitGroup(1);

void handler(int signum)
{
        printf("signum = %d\n",signum);
    gWaitGroup.done();
}

void fileIOCallback(WFFileIOTask *preadTask)
{
    cout<<"fileIOCallback is called"<<endl;
    SeriesContext *context = (SeriesContext*)series_of(preadTask)->get_context();
    cout<<"buf = "<<context->buf<<endl;
    context->resp->append_output_body(context->buf,strlen(context->buf));


}

void process(WFHttpTask *serverTask)
{
    cout<<"Process is called"<<endl;
    // 修改响应
    protocol::HttpResponse *resp = serverTask->get_resp();
    resp->set_http_version("HTTP/1.1");
    resp->set_status_code("200");
    resp->set_reason_phrase("ok");
    resp->set_header_pair("Content-type","text/html");
    // workflow框架会自动加入s首部字段 connection keep-aline
    resp->append_output_body("<html>Hello</html>");

    protocol::HttpRequest *req = serverTask->get_req();
    string method = req->get_method();
    if(method == "GET")
    {
        int fd = open("postform.html",O_RDONLY);
        SeriesContext *context = new SeriesContext();
        context->resp = resp;
        series_of(serverTask)->set_context(context);
        WFFileIOTask *preadTask = WFTaskFactory::create_pread_task(fd,context->buf,4096,0,fileIOCallback);
        series_of(serverTask)->push_back(preadTask);
    }
    else
    {
        resp->append_output_body("<html>Yes</html>");
    }


}

int main()
{
   signal(SIGINT,handler);
   WFHttpServer server(process);
   server.start(1234); // listen 1234端口
   gWaitGroup.wait();
}

wfrest的使用

在这里插入图片描述


#include <54func.h>
#include <iostream>
using std::cout;
using std::endl;
#include <workflow/WFFacilities.h>
#include <wfrest/HttpServer.h>
static WFFacilities::WaitGroup waitGroup(1);
void sighandler(int num)
{
    printf("sig %d is coming\n", num);
    // 将计数器的值减1
    waitGroup.done();
}
int main()
{
    using std::string;
    signal(SIGINT, sighandler);
    using namespace wfrest;
    HttpServer httpserver;
    httpserver.GET("/wfrest/test0",
                   [](const HttpReq *, HttpResp *resp)
                   {
                       // 使用workflow的方式设置响应
                       resp->append_output_body("hello, wfrest client");
                   });
    httpserver.GET("/wfrest/query",
                   [](const HttpReq *req, HttpResp *resp)
                   {
                       // uri的查询参数部分
                       cout << "username:" << req->query("username") << endl;
                       auto queryList = req->query_list();
                       for (auto &query : queryList)
                       {
                           cout << query.first << ": " << query.second << endl;
                       }
                       resp->append_output_body("hello, wfrest client1");
                   });
    httpserver.POST("/wfrest/body",
                    [](const HttpReq *req, HttpResp *resp)
                    {
                        // 请求体
                        string body = req->body();
                        cout << "body:" << body << endl;
                        resp->append_output_body("hello, wfrest client");
                    });
    httpserver.POST("/wfrest/urlencoded",
                    [](const HttpReq *req, HttpResp *resp)
                    {
                        // URLENCODED类型的请求体
                        if (req->content_type() == APPLICATION_URLENCODED)
                        {
                            auto formKV = req->form_kv();
                            for (auto &elem : formKV)
                            {
                                cout << elem.first << ": " << elem.second << endl;
                            }
                        }
                        resp->append_output_body("hello, wfrest client");
                    });
    httpserver.POST("/wfrest/formdata",
                    [](const HttpReq *req, HttpResp *resp)
                    {
                        // form_data类型的请求体
                        if (req->content_type() == MULTIPART_FORM_DATA)
                        {
                            auto form = req->form();
                            for (auto &elem : form)
                            {
                                cout << elem.first << ": " << elem.second.first
                                     << endl;
                                cout << elem.second.second << endl;
                            }
                        }
                        resp->append_output_body("hello, wfrest client");
                    });
    if (httpserver.track().start(1234) == 0)
    {
        // 列出当前服务器上部署的服务
        httpserver.list_routes();
        waitGroup.wait();
        httpserver.stop();
    }
    else
    {
        printf("HttpServer start failed.\n");
    }
    return 0;
}
  • 更多功能

简化首部字段操作

resp->add_header_pair()    // 添加首部字段
resp_set_header_pair() // 首部字段已经存在

resp->headers["Location"] = ""; // 没有就添加有就修改

简化查询参数操作

在这里插入图片描述

  • 简化登录业务
    在这里插入图片描述

#include <54func.h>
#include <iostream>
using std::cout;
using std::endl;
#include <workflow/WFFacilities.h>
#include <workflow/MySQLResult.h>
#include <workflow/MySQLUtil.h>
#include <wfrest/HttpServer.h>
#include <wfrest/json.hpp>
using std::vector;
static WFFacilities::WaitGroup waitGroup(1);
void sighandler(int num)
{
    printf("sig %d is coming\n", num);
    // 将计数器的值减1
    waitGroup.done();
}
int main()
{
    using std::string;
    signal(SIGINT, sighandler);
    using namespace wfrest;
    HttpServer httpserver;
    // String可以自动设置首部字段
    httpserver.GET("/wfrest/test0",
                   [](const HttpReq *, HttpResp *resp)
                   {
                       resp->String("hello,wfrest client2");
                   });
    // 部署静态资源
    httpserver.GET("/wfrest/file",
                   [](const HttpReq *, HttpResp *resp)
                   {
                       resp->File("postform.html");
                   });
    // 响应JSON
    httpserver.GET("/wfrest/json",
                   [](const HttpReq *, HttpResp *resp)
                   {
                       Json data;
                       data["username"] = "liubei";
                       data["password"] = "123";
                       resp->Json(data);
                   });
    // MySQL默认结果
    httpserver.GET("/wfrest/mysql0",
                   [](const HttpReq *, HttpResp *resp)
                   {
                       string url("mysql://root:123@localhost");
                       string sql("select * from mycloud.tbl_user_token");
                       resp->MySQL(url, sql);
                   });
    // MySQL的Json结果
    httpserver.GET("/wfrest/mysql1",
                   [](const HttpReq *, HttpResp *resp)
                   {
                       string url("mysql://root:123@localhost");
                       string sql("select * from mycloud.tbl_user_token");
                       // json指针指向的就是MySQL的结果集
                       resp->MySQL(url, sql, [resp](Json *json)
                                   {
string msg = (*json)["result_set"][0]["rows"][0][1];
resp->String(msg); });
                   });
    // MySQL cursor
    httpserver.GET("/wfrest/mysql2",
                   [](const HttpReq *, HttpResp *resp)
                   {
                       string url("mysql://root:123@localhost");
                       string sql("select * from mycloud.tbl_user_token");
                       using namespace protocol;
                       // pcursor指针指向的就是MySQL的结果集的迭代器
                       resp->MySQL(url, sql, [resp](MySQLResultCursor *pcursor)
                                   {
std::vector<std::vector<MySQLCell>> matrix;
pcursor->fetch_all(matrix);
string msg = matrix[0][2].as_string();
resp->String(msg); });
                   });
    // 在wfrest中显式使用序列
    httpserver.GET("/wfrest/series",
                   [](const HttpReq *, HttpResp *resp, SeriesWork *series)
                   {
                       auto timerTask = WFTaskFactory::create_timer_task(1000 *
                                                                             1000,
                                                                         [resp](WFTimerTask *)
                                                                         {
                                                                             printf("timerCallback is running.\n");
                                                                             resp->String("timer callback");
                                                                         });
                       series->push_back(timerTask);
                   });
    // 序列配合mysql任务
    httpserver.GET("/wfrest/mysql3",
                   [](const HttpReq *, HttpResp *httpResp, SeriesWork *series)
                   {
                       string url("mysql://root:123@localhost");
                       auto mysqlTask =
                           WFTaskFactory::create_mysql_task(url, 1,
                                                            [httpResp](WFMySQLTask *mysqltask)
                                                            {
                                                                // 0. 对任务的状态进行检测
                                                                int state = mysqltask->get_state();
                                                                int error = mysqltask->get_error();
                                                                if (state != WFT_STATE_SUCCESS)
                                                                {
                                                                    printf("%s\n", WFGlobal::get_error_string(state,
                                                                                                              error));
                                                                    return;
                                                                }
                                                                // 1. 检测SQL语句是否存在语法错误
                                                                auto resp = mysqltask->get_resp();
                                                                if (resp->get_packet_type() == MYSQL_PACKET_ERROR)
                                                                {
                                                                    printf("ERROR %d: %s\n", resp->get_error_code(),
                                                                           resp->get_error_msg().c_str());
                                                                    return;
                                                                }
                                                                printf("sql sentence is ok.\n");
                                                                using namespace protocol;
                                                                MySQLResultCursor cursor(resp);
                                                                if (cursor.get_cursor_status() == MYSQL_STATUS_OK)
                                                                {
                                                                    printf("Query OK. %llu row affected.\n",
                                                                           cursor.get_affected_rows());
                                                                }
                                                                else if (cursor.get_cursor_status() ==
                                                                         MYSQL_STATUS_GET_RESULT)
                                                                {
                                                                    // 读操作
                                                                    vector<vector<MySQLCell>> matrix;
                                                                    cursor.fetch_all(matrix);
                                                                    string msg = matrix[1][1].as_string();
                                                                    httpResp->String(msg);
                                                                }
                                                            });
                       string sql("select * from mycloud.tbl_user_token");
                       mysqlTask->get_req()->set_query(sql);
                       series->push_back(mysqlTask);
                   });
    if (httpserver.track().start(1234) == 0)
    {
        // 列出当前服务器上部署的服务
        httpserver.list_routes();
        waitGroup.wait();
        httpserver.stop();
    }
    else
    {
        printf("HttpServer start failed.\n");
    }
    return 0;
}

wfrest解析报文体

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

解析x-www-form-urlencoded(传简单消息)

#include <54func.h>
#include <iostream>
#include<map>
using std::cout;
using std::endl;
using std::cerr;
using std::map;
#include <workflow/WFFacilities.h>
#include <wfrest/HttpServer.h>
static WFFacilities::WaitGroup waitGroup(1);
void sighandler(int num)
{
    printf("sig %d is coming\n", num);
    // 将计数器的值减1
    waitGroup.done();
}
int main()
{
    using std::string;
    using namespace wfrest;
    signal(SIGINT, sighandler);
    wfrest::HttpServer server;
    server.GET("/abc",[](const wfrest::HttpReq *req,wfrest::HttpResp *resp){
               resp->headers["key"] = "value";
               });
    server.POST("/def",[](const HttpReq *req,HttpResp *resp){
                // 头体: a=b&c=d&e=f
                if(req->content_type() == APPLICATION_URLENCODED)
                {
                    map<string,string> body = req->form_kv();
                    for(auto &myPair:body)
                    {
                        cerr<<"key = "<<myPair.first<<",value = "<<myPair.second<<endl;
                    }
                }
                });
    if (server.start(1234) == 0)
    {
        // 列出当前服务器上部署的服务
        server.list_routes();
        waitGroup.wait();
        server.stop();
    }
    else
    {
        printf("HttpServer start failed.\n");
    }
    return 0;
}

解析from-data(传文件)

在这里插入图片描述

// 注意框架,要求单个文件不能上传超过128M

// 会下载
    server.POST("/upload",[](const HttpReq * req,HttpResp *resp){
                  resp->File("./upload.html");
                    if(req->content_type() == MULTIPART_FORM_DATA)
                    {
                        map<string,pair<string,string>> &formdata = req->form();
                        for(auto &mypair : formdata)
                        {
                            cerr<<"key = "<<mypair.first
                            <<",value1 = "<<mypair.second.first
                            <<",value2 = "<<mypair.second.second<<endl;
                        }
                    }
               });
    // z只会展示
    server.GET("/upload",[](const HttpReq * req,HttpResp *resp){
                  resp->File("./upload.html");
                  });
                  server.Static("/static","./static_res");

在这里插入图片描述

部署静态资源

server.GET("/postform.html",[](const HttpReq *req,HttpResp *resp){
               resp->File("postform.html");
               });

在这里插入图片描述

  • 一次性部署多个文件
    在这里插入图片描述
    在这里插入图片描述
int main()
{
    using std::string;
    using namespace wfrest;
    signal(SIGINT, sighandler);
    wfrest::HttpServer server;
    server.GET("/abc",[](const wfrest::HttpReq *req,wfrest::HttpResp *resp){
               resp->headers["key"] = "value";
               });
    server.POST("/def",[](const HttpReq *req,HttpResp *resp){
                // 头体: a=b&c=d&e=f
                if(req->content_type() == APPLICATION_URLENCODED)
                {
                    map<string,string> body = req->form_kv();
                    for(auto &myPair:body)
                    {
                        cerr<<"key = "<<myPair.first<<",value = "<<myPair.second<<endl;
                    }
                }
                });
    server.GET("/postform.html",[](const HttpReq *req,HttpResp *resp){
               resp->File("postform.html");
               });
    server.Static("/static","./static_res");
    if (server.start(1234) == 0)
    {
        // 列出当前服务器上部署的服务
        server.list_routes();
        waitGroup.wait();
        server.stop();
    }
    else
    {
        printf("HttpServer start failed.\n");
    }
    return 0;
}

解析json报文体格式

#include<wfrest/json.hpp>
using Json = nlohmann::json;
    server.POST("/json", [](const HttpReq *req, HttpResp *resp) {
                try {
                string body = req->body();
                Json info = Json::parse(body);
                string filename = info["filename"];
                string filecontent = info["filecontent"];
                int size = info["filesize"];
                cerr << filename << filecontent << size << endl;
                resp->String("OK"); // 添加响应,以便客户端知道请求成功
                } catch (const Json::parse_error &e) {
                cerr << "JSON parse error: " << e.what() << endl;
                resp->String("Invalid JSON format");
                } catch (const Json::out_of_range &e) {
                cerr << "JSON key error: " << e.what() << endl;
                resp->String("Missing required fields in JSON");
                }
                });// 删除其中一个定义

发送SQL

直接将结果返给前端

server.GET("/mysql",[](const HttpReq *res,HttpResp *resp){
                             resp->MySQL("mysql://root:123@localhost","select * from cloudisk.tbl_user_token");
                             });

在这里插入图片描述

使用三参数版本,调用序列进行回调

server.GET("/mysql1", [](const HttpReq *req, HttpResp *resp, SeriesWork *series)
               { WFMySQLTask *mysqlTask =
                     WFTaskFactory::create_mysql_task("mysql://root:123@localhost", 0,
                                                      [](WFMySQLTask *mysqlTask)
                                                      {
                                                          // step 1 检查连接的状态
                                                          if (mysqlTask->get_state() != WFT_STATE_SUCCESS)
                                                          {
                                                              std::cerr << "error msg :" << WFGlobal::get_error_string(mysqlTask->get_state(), mysqlTask->get_error());
                                                              return;
                                                          }
                                                          protocol::MySQLResponse *resp = mysqlTask->get_resp();
                                                          protocol::MySQLResultCursor cursor(mysqlTask->get_resp());
                                                          // step 2 检查mysql任务的状态
                                                          if (resp->get_packet_type() == MYSQL_PACKET_ERROR)
                                                          {
                                                              std::cerr << "ERROR, error code = " << resp->get_error_code()
                                                                        << " msg = " << resp->get_error_msg();
                                                              return;
                                                          }
                                                          do
                                                          { // step 3 遍历结果集合
                                                              // step 4 判断指令的类型是 读 select 写 update insert delete from alter
                                                              if (cursor.get_cursor_status() == MYSQL_STATUS_OK)
                                                              {
                                                                  // 说明是写操作
                                                                  std::cerr << "OK, " << cursor.get_affected_rows() << " rows affected."
                                                                            << cursor.get_warnings() << " warnings. insert_id = " << cursor.get_insert_id() << ".\n";
                                                              }
                                                              else if (cursor.get_cursor_status() == MYSQL_STATUS_GET_RESULT)
                                                              {
                                                                  // 说明sql语句是读操作
                                                                  std::cerr << "field count = " << cursor.get_field_count()
                                                                            << " rows count = " << cursor.get_rows_count() << "\n";
                                                                  // 找到所有域的信息
                                                                  const protocol::MySQLField *const *fields = cursor.fetch_fields();
                                                                  for (int i = 0; i < cursor.get_field_count(); ++i)
                                                                  {
                                                                      std::cerr << "database = " << fields[i]->get_db()
                                                                                << " table = " << fields[i]->get_table()
                                                                                << " fieldname = " << fields[i]->get_name()
                                                                                << " fieldtype = " << datatype2str(fields[i]->get_data_type())
                                                                                << "\n";
                                                                  }
                                                                  // 取出表格当中的所有内容
                                                                  std::vector<std::vector<protocol::MySQLCell>> rows;
                                                                  cursor.fetch_all(rows);
                                                                  for (unsigned int j = 0; j < rows.size(); ++j)
                                                                  {
                                                                      for (unsigned int i = 0; i < rows[j].size(); ++i)
                                                                      {
                                                                          if (rows[j][i].is_int())
                                                                          {
                                                                              std::cerr << rows[j][i].as_int() << " ";
                                                                          }
                                                                          else if (rows[j][i].is_string())
                                                                          {
                                                                              std::cerr << rows[j][i].as_string() << " ";
                                                                          }
                                                                          else if (rows[j][i].is_datetime())
                                                                          {
                                                                              std::cerr << rows[j][i].as_datetime() << " ";
                                                                          }
                                                                      }
                                                                      std::cerr << "\n";
                                                                  }
                                                              }
                                                          } while (cursor.next_result_set()); // 多个sql指令合在一起的情况
                                                          // cursor.next_result_set(); // 当执行多个sql语句时

                                                      });

        mysqlTask->get_req()->set_query("select * from cloudisk.tbl_user_token");
        series->push_back(mysqlTask); });

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值