【项目】仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器(Http测试板块)

本文主要是介绍【项目】仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器(Http测试板块),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【项目】仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器(Http测试板块)

  • 一、使用Http网页界面
    • 1、main.cc原码和index.html原码
    • 2、运行结果
      • (1)测试结果1:用index.html内部的代码
      • (2)测试结果2:用hello
      • (3)测试结果3:用login
      • (4)测试结果4:hello?username=jrh&password=123456
  • 二、长连接的测试一
    • 1、代码部分
    • 2、测试结果(错误结果)
      • (1)不是长连接,查看错误原因
      • (2)通过Close看是否进入
      • (3)Request中的Close函数打印调试
      • (4)去掉尾部\n
      • (5)去掉空格尝试1
      • (6)去掉空格尝试2(成功)
  • 三、长连接的测试二
    • 1、代码部分
    • 2、测试结果
  • 四、错误请求测试
    • 1、代码部分
      • (1)代码一
      • (2)代码二
    • 2、测试结果
      • (1)运行结果1
      • (2)运行结果2
  • 五、HTTP服务器业务处理超时测试
    • 1、代码部分修改
    • 2、代码部分
    • 3、测试结果
  • 六、HTTP服务器同时多条请求测试
    • 1、代码部分
    • 2、运行结果
  • 七、HTTP服务器大文件传输测试
    • 1、代码部分
    • 2、测试结果
  • 八、HTTP服务器大文件传输测试
    • 效果展示


一、使用Http网页界面

1、main.cc原码和index.html原码

#include "http.hpp"
#define WWWROOT "./wwwroot/"
std::string RequestStr(const HttpRequest& req)
{std::stringstream ss;ss << req._method << " " << req._path << " " << req._version << "\r\n";for (auto& it : req._params){ss << it.first << ": " << it.second << "\r\n";}for (auto& it : req._headers){ss << it.first << ": " << it.second << "\r\n";}ss << "\r\n";ss << req._body;return ss.str();
}
void Hello(const HttpRequest& req, HttpResponse* rsp)
{rsp->SetContent(RequestStr(req), "text/plain");
}
void Login(const HttpRequest& req, HttpResponse* rsp)
{rsp->SetContent(RequestStr(req), "text/plain");
}
void PutFile(const HttpRequest& req, HttpResponse* rsp)
{std::string pathname = WWWROOT + req._path;rsp->SetContent(RequestStr(req), "text/plain");
}
void DeleteFile(const HttpRequest& req, HttpResponse* rsp)
{rsp->SetContent(RequestStr(req), "text/plain");
}
int main()
{HttpServer server(8850);server.SetThreadCount(3);server.SetBaseDir(WWWROOT); // 设置静态资源根目录,告诉服务器有静态资源到来需要到哪里找资源文件server.Get("/hello", Hello);server.Post("/login", Login);server.Put("/xxx.txt", PutFile);server.Delete("/xxx.txt", DeleteFile);server.Listen(); // 直接开始启动了return 0;
}
// index.html
<html><head><meta charset="utf8"></head><body><form action="/login" method="post"><input type="text" name="username"><br/><input type="password" name="password"><br/><input type="submit" value="提交" name="submit"></form></body>
</html>

2、运行结果

运行前记得开放端口哦!

(1)测试结果1:用index.html内部的代码

在这里插入图片描述
网页界面如下
在这里插入图片描述

(2)测试结果2:用hello

网页界面如下:
在这里插入图片描述

(3)测试结果3:用login

网页界面如下:
在这里插入图片描述
按一下提交:

在这里插入图片描述

(4)测试结果4:hello?username=jrh&password=123456

网页界面如下:
在这里插入图片描述

二、长连接的测试一

1、代码部分

// client1.cc
// 长连接测试1:创建一个客户端,持续给客户端发消息,直到超过超时时间看是否正常
#include "../source/server.hpp"int main()
{Socket clent_socket;clent_socket.Client(8888, "127.0.0.1");std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";while(1){assert(clent_socket.Send(req.c_str(), req.size()) != -1);char buff[1024] = { 0 };assert(clent_socket.Recv(buff, 1023));DEBLOG("[%s]", buff);sleep(3);}clent_socket.Close();return 0;
}
// Makefile
all:client1
client1:client1.ccg++ -o $@ $^ -std=c++11 -lpthreadserver:server.ccg++ -o $@ $^ -std=c++11 -lpthread
Client:tcp_cli.ccg++ -o $@ $^ -std=c++11 -lpthread
Server:tcp_svr.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f Client Server server

2、测试结果(错误结果)

(1)不是长连接,查看错误原因

在这里插入图片描述

(2)通过Close看是否进入

我们此时通过HttpServer中的Close函数进行打印看一下有没有进去!
在这里插入图片描述

在这里插入图片描述

(3)Request中的Close函数打印调试

我们此时直接去request中的Close中进行日志打印一下:
在这里插入图片描述
在这里插入图片描述
发现,有头部这个Connection,但是进行相当的时候是错误的,我们看上面的[keep-alive]但是上面打印的完全不是这样的,所以我们接下来需要去HttpContext中进行修改,我们直接在后面加上末尾去掉换行字符和回车字符!

(4)去掉尾部\n

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

(5)去掉空格尝试1

能好一点,但是还是不对,我起初的思路在于把前面一个空格给去掉,所以在前面用了substr/erase,我们先看一下结果吧:
在这里插入图片描述

在这里插入图片描述
发现什么都没有了,我的天,我理解了一遍代码发现它是从后面才开始拼接上去的,所以我们需要在后面进行理解,发现此时value需要到+2这个位置往后拼接才可,因为刚好+2是跳过一个空格了,我们看一下是不是了:

(6)去掉空格尝试2(成功)

在这里插入图片描述
在这里插入图片描述
成功!通过这次调试,发现理清代码逻辑和进行日志打印是很重要的!

三、长连接的测试二

1、代码部分

// client2.cc
// 长连接测试2:创建一个客户端,给服务器发送一次数据后,不动了,查看服务器是否会正常的超时关闭连接
#include "../source/server.hpp"int main()
{Socket clent_socket;clent_socket.Client(8888, "127.0.0.1");std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";while(1){assert(clent_socket.Send(req.c_str(), req.size()) != -1);char buff[1024] = { 0 };assert(clent_socket.Recv(buff, 1023));DEBLOG("[%s]", buff);sleep(15);}clent_socket.Close();return 0;
}
// Makefile
all:client2
client2:client2.ccg++ -o $@ $^ -std=c++11 -lpthread
client1:client1.ccg++ -o $@ $^ -std=c++11 -lpthreadserver:server.ccg++ -o $@ $^ -std=c++11 -lpthread
Client:tcp_cli.ccg++ -o $@ $^ -std=c++11 -lpthread
Server:tcp_svr.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f Client Server server

2、测试结果

在这里插入图片描述

四、错误请求测试

1、代码部分

(1)代码一

// client3.cc
/*给服务器发送一个数据,告诉服务器要发送1024字节的数据,但是实际发送的数据不足1024,查看服务器处理结果*/
/*1. 如果数据只发送一次,服务器将得不到完整请求,就不会进行业务处理,客户端也就得不到响应,最终超时关闭连接2. 连着给服务器发送了多次小的请求,服务器会将后边的请求当作前边请求的正文进行处理,而后便处理的时候有可能就会因为处理错误而关闭连接
*/#include "../source/server.hpp"int main()
{Socket client_sock;client_sock.Client(8888, "127.0.0.1");std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 100\r\n\r\njiangrenhai"; // 不到100个字节while(1) {assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);char buf[1024] = {0};assert(client_sock.Recv(buf, 1023));DEBLOG("[%s]", buf);sleep(3);}client_sock.Close();return 0;
}
// Makefile
all:client3
client3:client3.ccg++ -o $@ $^ -std=c++11 -lpthread
client2:client2.ccg++ -o $@ $^ -std=c++11 -lpthread
client1:client1.ccg++ -o $@ $^ -std=c++11 -lpthreadserver:server.ccg++ -o $@ $^ -std=c++11 -lpthread
Client:tcp_cli.ccg++ -o $@ $^ -std=c++11 -lpthread
Server:tcp_svr.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f Client Server server

(2)代码二

// client3.cc
/*给服务器发送一个数据,告诉服务器要发送1024字节的数据,但是实际发送的数据不足1024,查看服务器处理结果*/
/*1. 如果数据只发送一次,服务器将得不到完整请求,就不会进行业务处理,客户端也就得不到响应,最终超时关闭连接2. 连着给服务器发送了多次小的请求,服务器会将后边的请求当作前边请求的正文进行处理,而后便处理的时候有可能就会因为处理错误而关闭连接
*/#include "../source/server.hpp"int main()
{Socket client_sock;client_sock.Client(8888, "127.0.0.1");std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 100\r\n\r\njiangrenhai"; // 不到100个字节while(1) {assert(client_sock.Send(req.c_str(), req.size()) != -1);assert(client_sock.Send(req.c_str(), req.size()) != -1);assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);//assert(client_sock.Send(req.c_str(), req.size()) != -1);char buf[1024] = {0};assert(client_sock.Recv(buf, 1023));DEBLOG("[%s]", buf);sleep(3);}client_sock.Close();return 0;
}

2、测试结果

(1)运行结果1

在这里插入图片描述

我们的解决方法为:发现OnMessage的回调函数出问题了!
在这里插入图片描述
当我们的请求数据很多的情况下,程序不退出,那么我们的OVER没有使用,所以我们加入我们注释的那几行代码:
在这里插入图片描述
在这里插入图片描述
是预期结果!

(2)运行结果2

在这里插入图片描述

五、HTTP服务器业务处理超时测试

1、代码部分修改

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

2、代码部分

// client4.cc
/* 业务处理超时,查看服务器的处理情况当服务器达到了一个性能瓶颈,在一次业务处理中花费了太长的时间(超过了服务器设置的非活跃超时时间)1. 在一次业务处理中耗费太长时间,导致其他的连接也被连累超时,其他的连接有可能会被拖累超时释放假设现在  12345描述符就绪了, 在处理1的时候花费了30s处理完,超时了,导致2345描述符因为长时间没有刷新活跃度1. 如果接下来的2345描述符都是通信连接描述符,如果都就绪了,则并不影响,因为接下来就会进行处理并刷新活跃度2. 如果接下来的2号描述符是定时器事件描述符,定时器触发超时,执行定时任务,就会将345描述符给释放掉这时候一旦345描述符对应的连接被释放,接下来在处理345事件的时候就会导致程序崩溃(内存访问错误)因此这时候,在本次事件处理中,并不能直接对连接进行释放,而应该将释放操作压入到任务池中,等到事件处理完了执行任务池中的任务的时候,再去释放
*/#include "../source/server.hpp"int main()
{signal(SIGCHLD, SIG_IGN);for (int i = 0; i < 10; i++) {pid_t pid = fork();if (pid < 0) {DEBLOG("FORK ERROR!!!");return -1;}else if (pid == 0) {Socket cli_sock;cli_sock.Client(8888, "127.0.0.1");std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";while(1) {assert(cli_sock.Send(req.c_str(), req.size()) != -1);char buf[1024] = {0};assert(cli_sock.Recv(buf, 1023));DEBLOG("[%s]", buf);}cli_sock.Close();exit(0);}}while(1) sleep(1);return 0;
}

3、测试结果

在这里插入图片描述

六、HTTP服务器同时多条请求测试

1、代码部分

在这里插入图片描述

// client5.cc
/*一次性给服务器发送多条数据,然后查看服务器的处理结果*/
/*每一条请求都应该得到正常处理*/#include "../source/server.hpp"int main()
{Socket cli_sock;cli_sock.Client(8888, "127.0.0.1");std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";req += "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";req += "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";while(1) {assert(cli_sock.Send(req.c_str(), req.size()) != -1);char buf[1024] = {0};assert(cli_sock.Recv(buf, 1023));DEBLOG("[%s]", buf);sleep(3);}cli_sock.Close();return 0;
}

2、运行结果

在这里插入图片描述

七、HTTP服务器大文件传输测试

1、代码部分

// client6.cc
/*大文件传输测试,给服务器上传一个大文件,服务器将文件保存下来,观察处理结果*/
/*上传的文件,和服务器保存的文件一致
*/
#include "../source/http/http.hpp"int main()
{Socket cli_sock;cli_sock.Client(8085, "127.0.0.1");std::string req = "PUT /1234.txt HTTP/1.1\r\nConnection: keep-alive\r\n";std::string body;Util::ReadFile("./hello.txt", &body);req += "Content-Length: " + std::to_string(body.size()) + "\r\n\r\n";assert(cli_sock.Send(req.c_str(), req.size()) != -1);assert(cli_sock.Send(body.c_str(), body.size()) != -1);char buf[1024] = {0};assert(cli_sock.Recv(buf, 1023));DEBLOG("[%s]", buf);sleep(3);cli_sock.Close();return 0;
}

2、测试结果

在这里插入图片描述

八、HTTP服务器大文件传输测试

效果展示

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

这篇关于【项目】仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器(Http测试板块)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi