workflow系列教程(6)实现静态资源服务器

往期教程

如果觉得写的可以,请给一个点赞+关注支持一下
观看之前请先看,往期的博客教程,否则这篇博客没办法看懂

处理请求

我们不占用任何线程读取文件,而是产生一个异步的读文件任务,在读取完成之后回复请求。

再次说明一下,我们需要把完整回复数据读取到内存,才开始回复消息。所以不适合用来传输太大的文件。

cpp 复制代码
struct SeriesContext{
    WFHttpTask *serverTask;	//所属workflow任务
    int fd;					//文件fd
    char *buf;				//文件数据缓冲区
    size_t filesize;		//文件大小
};

void process(WFHttpTask *serverTask){
    // 1 创建文件IO任务
    size_t filesize = 614;
    int fd = open("postform.html",O_RDONLY);
    char *buf = new char[filesize];
    auto IOTask = WFTaskFactory::create_pread_task(fd,buf,filesize,0,IOCallback);
    // 2 把文件IO任务加入到序列中
    series_of(serverTask)->push_back(IOTask);
    // 3 创建传递给IOTask的context
    SeriesContext *context = new SeriesContext;
    context->serverTask =  serverTask;
    context->fd = fd;
    context->buf = buf;
    context->filesize = filesize;
    series_of(serverTask)->set_context(context);
    // 4 设置序列的回调函数,释放所有资源
    series_of(serverTask)->set_callback([](const SeriesWork *series){
        fprintf(stderr,"series callback\n");
        SeriesContext * context = static_cast<SeriesContext *>(series->get_context());
        delete[] context->buf;
        close(context->fd);
        delete context;
    });
}

与HTTP反向代理产生一个新的http client任务不同,这里我们通过factory产生了一个pread任务。

WFTaskFactory.h里,我们可以看到相关的接口。

cpp 复制代码
struct FileIOArgs
{
    int fd;
    void *buf;
    size_t count;
    off_t offset;
};

...
using WFFileIOTask = WFFileTask<struct FileIOArgs>;
using fio_callback_t = std::function<void (WFFileIOTask *)>;
...

class WFTaskFactory
{
public:
    ...
    static WFFileIOTask *create_pread_task(int fd, void *buf, size_t count, off_t offset,
                                           fio_callback_t callback);

    static WFFileIOTask *create_pwrite_task(int fd, void *buf, size_t count, off_t offset,
                                            fio_callback_t callback);
    ...

    /* Interface with file path name */
	static WFFileIOTask *create_pread_task(const std::string& pathname, void *buf, size_t count, off_t offset,
                                           fio_callback_t callback);

    static WFFileIOTask *create_pwrite_task(const std::string& pathname, void *buf, size_t count, off_t offset,
                                            fio_callback_t callback);  
};

无论是pread还是pwrite,返回的都是WFFileIOTask。这与不区分sort或psort,不区分client或server task是一个道理。

除这两个接口还有preadv和pwritev,返回WFFileVIOTask,以及fsync,fdsync,返回WFFileSyncTask。可以在头文件里查看。

示例用了task的user_data域保存服务的全局数据。但对于大服务,推荐使用series context。

处理读文件结果及响应

将文件资源返回给客户端

cpp 复制代码
void IOCallback(WFFileIOTask *IOTask){
    SeriesContext *context = static_cast<SeriesContext *>(series_of(IOTask)->get_context());
    auto resp2client = context->serverTask->get_resp();
    resp2client->add_header_pair("Content-Type","text/html");
    resp2client->append_output_body(context->buf,context->filesize);
}

完整代码

postform.html

html 复制代码
<!DOCTYPE html>
<html>
    <head>
        <title>test</title>
    </head>
    <body> 
        <form  method="post" enctype="application/x-www-form-urlencoded">
            <div>
              <label for="username">username:</label>
              <input type="text" name="username">
            </div>
            <div>
              <label for="password">password:</label>
              <input type="text" name="password">
            </div>
            <div class="button">
                <button type="submit">Send your message</button>
            </div>
        </form>
    </body>
</html>
cpp 复制代码
#include "linuxheader.h"
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>
#include <workflow/HttpUtil.h>
static WFFacilities::WaitGroup waitGroup(1);
void sigHandler(int num){
    waitGroup.done();
    fprintf(stderr,"wait group is done\n");
}
struct SeriesContext{
    WFHttpTask *serverTask;
    int fd;
    char *buf;
    size_t filesize;
};
void IOCallback(WFFileIOTask *IOTask){
    SeriesContext *context = static_cast<SeriesContext *>(series_of(IOTask)->get_context());
    auto resp2client = context->serverTask->get_resp();
    resp2client->add_header_pair("Content-Type","text/html");
    resp2client->append_output_body(context->buf,context->filesize);
}
void process(WFHttpTask *serverTask){
    // 1 创建文件IO任务
    size_t filesize = 614;
    int fd = open("postform.html",O_RDONLY);
    char *buf = new char[filesize];
    auto IOTask = WFTaskFactory::create_pread_task(fd,buf,filesize,0,IOCallback);
    // 2 把文件IO任务加入到序列中
    series_of(serverTask)->push_back(IOTask);
    // 3 创建传递给IOTask的context
    SeriesContext *context = new SeriesContext;
    context->serverTask =  serverTask;
    context->fd = fd;
    context->buf = buf;
    context->filesize = filesize;
    series_of(serverTask)->set_context(context);
    // 4 设置序列的回调函数,释放所有资源
    series_of(serverTask)->set_callback([](const SeriesWork *series){
        fprintf(stderr,"series callback\n");
        SeriesContext * context = static_cast<SeriesContext *>(series->get_context());
        delete[] context->buf;
        close(context->fd);
        delete context;
    });
}
int main(){
    signal(SIGINT,sigHandler);
    WFHttpServer server(process);
    if(server.start(1234) == 0){
        waitGroup.wait();
        server.stop();
    }
    else{
        perror("server start failed\n");
        return -1;
    }
    return 0;   
}
相关推荐
小程序面包园9 分钟前
Python函数缺省参数的 “ 坑 ” (与C++对比学习)
开发语言·c++·python·学习
爱技术的小伙子20 分钟前
Docker容器基础:Docker的安装与基本使用
linux·运维·服务器·docker
菜鸟赵大宝29 分钟前
Visual Studio编译优化选项
c++·visual studio
北岛寒沫33 分钟前
算法刷题笔记 单调栈(C++实现)
c++·笔记·算法
一条闲鱼。34 分钟前
C++ 文件读写
c++·读写文件
imred36 分钟前
C++:std::function的libc++实现
c++·stl·template·function·libc++
jzwalliser41 分钟前
洛谷 P1035 [NOIP2002 普及组] 级数求和
c++·python·算法
汀小烟1 小时前
使用静态成员函数统计学生平均成绩
c语言·开发语言·数据结构·c++·vscode
我要成为C++领域大神1 小时前
【高性能服务器】select模型
linux·服务器·c语言·开发语言·网络·tcp·io多路复用
LeoLei80602 小时前
新特性之C++17
开发语言·c++