workflow系列教程(5-1)HTTP Server

2023-12-20 14:45

本文主要是介绍workflow系列教程(5-1)HTTP Server,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

往期教程

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

观看之前请先看,往期的博客教程,否则这篇博客没办法看懂

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

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

  • C++异步网络库workflow系列教程(2)redis任务

  • workflow系列教程(3)Series串联任务流

  • workflow系列教程(4)Parallel并联任务流

创建与启动http server

本示例里,我们采用http server的默认参数。创建和启动过程非常简单。

  • process为设置的异步回调函数
  • server.start(port):中port参数表示监听的端口号
WFHttpServer server(process);
if (server.start(port) == 0)
{pause();server.stop();
}

start()接口有好几个重载函数,在WFServer.h里,可以看到如下一些接口:

class WFServerBase
{
public:/* To start TCP server. */int start(unsigned short port);int start(int family, unsigned short port);int start(const char *host, unsigned short port);int start(int family, const char *host, unsigned short port);int start(const struct sockaddr *bind_addr, socklen_t addrlen);/* To start an SSL server */int start(unsigned short port, const char *cert_file, const char *key_file);int start(int family, unsigned short port,const char *cert_file, const char *key_file);int start(const char *host, unsigned short port,const char *cert_file, const char *key_file);int start(int family, const char *host, unsigned short port,const char *cert_file, const char *key_file);int start(const struct sockaddr *bind_addr, socklen_t addrlen,const char *cert_file, const char *key_file);/* For graceful restart or multi-process server. */int serve(int listen_fd);int serve(int listen_fd, const char *cert_file, const char *key_file);/* Get the listening address. Used when started a server on a random port. */int get_listen_addr(struct sockaddr *addr, socklen_t *addrlen) const;
};

这些接口都比较好理解。任何一个start函数,当端口号为0时,将使用随机端口。此时用户可能需要在server启动完成之后通过get_listen_addr获得实际监听地址。

http echo server的业务逻辑

我们看到在构造http server的时候,传入了一个process参数,这也是一个std::function,定义如下:

using http_process_t = std::function<void (WFHttpTask *)>;
using WFHttpServer = WFServer<protocol::HttpRequest, protocol::HttpResponse>;template<>
WFHttpServer::WFServer(http_process_t proc) :WFServerBase(&HTTP_SERVER_PARAMS_DEFAULT),process(std::move(proc))
{
}

其实这个http_proccess_t和的http_callback_t类型是完全一样的。都是处理一个WFHttpTask。
对server来讲,我们的目标就是根据request,填写好response。
同样我们用一个普通函数实现process。逐条读出request的http header写入html页面。

void process(WFHttpTask *server_task)
{protocol::HttpRequest *req = server_task->get_req();protocol::HttpResponse *resp = server_task->get_resp();long seq = server_task->get_task_seq();protocol::HttpHeaderCursor cursor(req);std::string name;std::string value;char buf[8192];int len;/* Set response message body. */resp->append_output_body_nocopy("<html>", 6);len = snprintf(buf, 8192, "<p>%s %s %s</p>", req->get_method(),req->get_request_uri(), req->get_http_version());resp->append_output_body(buf, len);while (cursor.next(name, value)){len = snprintf(buf, 8192, "<p>%s: %s</p>", name.c_str(), value.c_str());resp->append_output_body(buf, len);}resp->append_output_body_nocopy("</html>", 7);/* Set status line if you like. */resp->set_http_version("HTTP/1.1");resp->set_status_code("200");resp->set_reason_phrase("OK");resp->add_header_pair("Content-Type", "text/html");resp->add_header_pair("Server", "Sogou WFHttpServer");if (seq == 9) /* no more than 10 requests on the same connection. */resp->add_header_pair("Connection", "close");struct sockaddr_in addr;socklen_t len = sizeof(addr);serverTask->get_peer_addr((sockaddr *)&addr,&len);if(addr.sin_family == AF_INET){fprintf(stderr,"sin_family:AF_INET\n");fprintf(stderr,"ip:%s\n", inet_ntoa(addr.sin_addr));fprintf(stderr,"port:%d\n",ntohs(addr.sin_port));}
}
  • set_http_version设置http版本
  • set_status_code设置状态码
  • set_reason_phrase设置响应dui’x

大多数HttpMessage相关操作之前已经介绍过了,在这里唯一的一个新操作是append_output_body()。
显然让用户生成完整的http body再传给我们并不太高效。用户只需要调用append接口,把离散的数据一块块扩展到message里就可以了。
append_output_body()操作会把数据复制走,另一个带_nocopy后缀的接口会直接引用指针,使用时需要注意不可以指向局部变量。
相关几个调用在HttpMessage.h可以看到其声明:

class HttpMessage
{
public:bool append_output_body(const void *buf, size_t size);bool append_output_body_nocopy(const void *buf, size_t size);...bool append_output_body(const std::string& buf);
};

再次强调,使用append_output_body_nocopy()接口时,buf指向的数据的生命周期至少需要延续到task的callback。
函数中另外一个变量seq,通过server_task->get_task_seq()得到,表示该请求是当前连接上的第几次请求,从0开始计。
程序中,完成10次请求之后就强行关闭连接,于是:

    if (seq == 9) /* no more than 10 requests on the same connection. */resp->add_header_pair("Connection", "close");

关闭连接还可以通过task->set_keep_alive()接口来完成,但对于http协议,还是推荐使用设置header的方式。
这个示例中,因为返回的页面很小,我们没有关注回复成功与否。

这篇关于workflow系列教程(5-1)HTTP Server的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/516419

相关文章

Ubuntu固定虚拟机ip地址的方法教程

《Ubuntu固定虚拟机ip地址的方法教程》本文详细介绍了如何在Ubuntu虚拟机中固定IP地址,包括检查和编辑`/etc/apt/sources.list`文件、更新网络配置文件以及使用Networ... 1、由于虚拟机网络是桥接,所以ip地址会不停地变化,接下来我们就讲述ip如何固定 2、如果apt安

PyCharm 接入 DeepSeek最新完整教程

《PyCharm接入DeepSeek最新完整教程》文章介绍了DeepSeek-V3模型的性能提升以及如何在PyCharm中接入和使用DeepSeek进行代码开发,本文通过图文并茂的形式给大家介绍的... 目录DeepSeek-V3效果演示创建API Key在PyCharm中下载Continue插件配置Con

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

Spring Boot整合log4j2日志配置的详细教程

《SpringBoot整合log4j2日志配置的详细教程》:本文主要介绍SpringBoot项目中整合Log4j2日志框架的步骤和配置,包括常用日志框架的比较、配置参数介绍、Log4j2配置详解... 目录前言一、常用日志框架二、配置参数介绍1. 日志级别2. 输出形式3. 日志格式3.1 PatternL

MySQL8.2.0安装教程分享

《MySQL8.2.0安装教程分享》这篇文章详细介绍了如何在Windows系统上安装MySQL数据库软件,包括下载、安装、配置和设置环境变量的步骤... 目录mysql的安装图文1.python访问网址2javascript.点击3.进入Downloads向下滑动4.选择Community Server5.

查询SQL Server数据库服务器IP地址的多种有效方法

《查询SQLServer数据库服务器IP地址的多种有效方法》作为数据库管理员或开发人员,了解如何查询SQLServer数据库服务器的IP地址是一项重要技能,本文将介绍几种简单而有效的方法,帮助你轻松... 目录使用T-SQL查询方法1:使用系统函数方法2:使用系统视图使用SQL Server Configu

CentOS系统Maven安装教程分享

《CentOS系统Maven安装教程分享》本文介绍了如何在CentOS系统中安装Maven,并提供了一个简单的实际应用案例,安装Maven需要先安装Java和设置环境变量,Maven可以自动管理项目的... 目录准备工作下载并安装Maven常见问题及解决方法实际应用案例总结Maven是一个流行的项目管理工具

SQL Server数据库迁移到MySQL的完整指南

《SQLServer数据库迁移到MySQL的完整指南》在企业应用开发中,数据库迁移是一个常见的需求,随着业务的发展,企业可能会从SQLServer转向MySQL,原因可能是成本、性能、跨平台兼容性等... 目录一、迁移前的准备工作1.1 确定迁移范围1.2 评估兼容性1.3 备份数据二、迁移工具的选择2.1

本地私有化部署DeepSeek模型的详细教程

《本地私有化部署DeepSeek模型的详细教程》DeepSeek模型是一种强大的语言模型,本地私有化部署可以让用户在自己的环境中安全、高效地使用该模型,避免数据传输到外部带来的安全风险,同时也能根据自... 目录一、引言二、环境准备(一)硬件要求(二)软件要求(三)创建虚拟环境三、安装依赖库四、获取 Dee