往期教程
如果觉得写的可以,请给一个点赞+关注支持一下
观看之前请先看,往期的博客教程,否则这篇博客没办法看懂
-
workFlow c++异步网络库编译教程与简介
-
C++异步网络库workflow入门教程(1)HTTP任务
-
C++异步网络库workflow系列教程(2)redis任务
-
workflow系列教程(3)Series串联任务流
-
workflow系列教程(4)Parallel并联任务流
-
workflow系列教程(5-1)HTTP Server
-
workflow系列教程(5-2)实现HTTP反向代理
处理请求
我们不占用任何线程读取文件,而是产生一个异步的读文件任务,在读取完成之后回复请求。
再次说明一下,我们需要把完整回复数据读取到内存,才开始回复消息。所以不适合用来传输太大的文件。
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里,我们可以看到相关的接口。
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。
处理读文件结果及响应
将文件资源返回给客户端文章来源:https://www.toymoban.com/news/detail-849516.html
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文章来源地址https://www.toymoban.com/news/detail-849516.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>
#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;
}
到了这里,关于workflow系列教程(6)实现静态资源服务器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!