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;   
}
相关推荐
JetComXCpp30 分钟前
给 Win32 窗口加上毛玻璃效果——纯 D3D11 实现,零依赖
c++
ysa0510302 小时前
【板子】二分答案(最大最小?)
c++·笔记·算法·板子
玖玥拾3 小时前
Unity 3D 笔记(十四)Unity/C# Socket 网络笔记3
服务器·网络·unity·c#
stolentime3 小时前
SP8549 MAIN75 - BST again题解
c++·算法·二叉树·深度优先·图论·记忆化搜索·组合数学
ziguo11223 小时前
C/C++ 错误处理全解:从 errno 到 C++ 异常
linux·c语言·c++·windows·visual studio
stolentime4 小时前
AT_pakencamp_2020_day1_k Gcd of Sum题解
c++·算法
2601_956121974 小时前
map_计蒜客T1271 完美K倍子数组
c++·算法
三8444 小时前
使用Samba/NFS实现文件共享/自动挂载共享目录/autofs自动挂载服务
linux·服务器·网络
高铭杰5 小时前
万物皆可KV(2)SurrealDB 存储布局分析
linux·服务器
王维同学5 小时前
IFEO Debugger、VerifierDlls 与 SilentProcessExit 配置
c++·windows·安全·注册表