【项目】仿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服务器大文件传输测试

效果展示

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2998292.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

《R语言与农业数据统计分析及建模》——多重共线性和逐步回归

一、多重共线性 多重共线性&#xff1a;在多元线性回归时&#xff0c;多个自变量之间存在高度相关关系&#xff0c;时模型估计失真或难以估计准确的情况。 一般地&#xff0c;多元线性回归中自变量间应尽量相互独立。常规模型诊断方法难以检测多重共线性。 1、案例解释 作物产…

汽车信息安全入门总结(2)

目录 1.引入 2.汽车信息安全技术 3.密码学基础知识 4.小结 1.引入 上篇汽车信息安全入门总结(1)-CSDN博客主要讲述了汽车信息安全应该关注的点&#xff0c;以及相关法规和标准&#xff0c;限于篇幅&#xff0c;继续聊信息安全相关技术以及需要掌握的密码学基础知识。 2.汽…

《Python语言科研绘图与学术图表绘制从入门到精通》解锁Python语言绘图魅力,让数据可视化成为你的科研利器!

本书特点 1.零基础高效入门&#xff1a;通过软件操作、实战案例及图文、代码结合的方式&#xff0c;实现从入门到精通的快速学习。 2.掌握多元科研绘图&#xff1a;涵盖科研绘图基础、各类图形绘制技巧&#xff0c;包括变量、极坐标、2D、3D及地理信息可视化等。 3.实用与艺术…

Linux快速安装Nginx和重新添加模块

目录 一、Nginx快速安装1、下载Nginx2、配置Nginx模块 二、Ngnix重新编译和安装模块 一、Nginx快速安装 1、下载Nginx 直接进入Nginx官网下载Linux最新稳定版本&#xff0c;我之前下载的版本是1.23.0。 2、配置Nginx模块 下载完后我把源码压缩文件解压放在/opt/appl/nginx…

使用Github+Picgo+npm实现免费图床

本文参考自 Akilar&#xff0c;原文地址&#xff1a;https://akilar.top/posts/3e956346/ Picgo的配置 Github图床仓库内容不能超过1GB&#xff0c;因为Github原则上是反对仓库图床化的&#xff0c;超过1GB之后会由人工审核仓库内容&#xff0c;如果仓库被发现用来做图床&…

2024最新UI发卡盗U/支持多语言/更新UI界面/支持多个主流钱包

本文来自&#xff1a;2024最新UI发卡盗U/支持多语言/更新UI界面/支持多个主流钱包 - 源码1688 应用介绍 简介&#xff1a; 2024最新UI发卡盗U/支持多语言/更新UI界面/支持多个主流钱包 自行检查后门&#xff0c;最好是部署智能合约后用合约地址来授权 包含转账支付页面盗U授…

STM32开启停止模式,用外部中断唤醒程序运行

今天学习了一下STM32的停止模式&#xff0c;停止模式下&#xff0c;所有外设的时钟和CPU的电源都会被关闭&#xff0c;所以会很省电&#xff0c;打破这种停止模式的方式就是外部中断可以唤醒停止模式。要想实现这个功能&#xff0c;其实设置很简单的&#xff0c;总共就需要两步…

Modelsim自动仿真平台的搭建

Modelsim自动仿真平台的搭建 如果要搭建自动仿真平台脚本那就需要更改下面3个文件。run_simulation.bat、complie.do和wave.do文件。注&#xff1a;前提是安装了modulsim并且配置好了环境变量&#xff0c;这里不过多介绍。 一、下面是run_simulation.bat文件的内容 : 注释的…

MyBatis 插件介绍及应用

MyBatis 插件介绍及应用 MyBatis 是一个持久层框架&#xff0c;它允许开发者自定义 SQL 语句并将其映射到 Java 对象中。MyBatis 提供了一种灵活的数据库操作方式&#xff0c;但随着项目的复杂度增加&#xff0c;一些通用功能如分页、缓存、事务管理等可能需要重复编写。为了解…

python部署linux

项目做完了&#xff0c;就涉及到了部署 部署 Python的打包部署方式有多种&#xff0c;具体取决于项目的需求、规模以及所使用的工具。以下是几种常见的Python打包部署方式&#xff1a; 使用pip安装&#xff1a;对于小型的Python库或工具&#xff0c;通常可以直接通过pip进行安…

踏上R语言之旅:解锁数据世界的神秘密码(四)

文章目录 前言一、多元线性回归1.多元线性回归模型的建立2.多元线性回归模型的检验 二、多元线性相关分析1.矩阵相关分析2.复相关分析 三、回归变量的选择方法1.变量选择准则2.变量选择的常用准则3.逐步回归分析 总结 前言 回归分析研究的主要对象是客观事物变量间的统计关系。…

【Redis 开发】Lua语言

Lua Lua语法 Lua语法 Lua是一种小巧的脚本语言&#xff0c;底层用C语言实现&#xff0c;为了嵌入式应用程序中 官网&#xff1a;https://www.lua.org/ 创建lua文件 touch hello.lua 运行lua文件 lua hello.lua 输出语句 print("Hello World!")数据类型 可以通过t…

UG NX二次开发(C++)-获取模型中所有的拉伸(Extrude)特征

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、在UG 12中创建几个拉伸特征3、UFun中获取对象类型4、通过NXOpen过渡5.测试结果1、前言 在采用UG NX二次开发时,有时需要在模型中获取特定的对象,比如拉伸特征、关联特征等等。但是通过…

Android log tag标签如am_pss意义

Android log tag标签如am_pss意义 Android输出日志中不同的标签代表不同的意义&#xff0c;比如 am_pss&#xff0c;则代表内存回收&#xff08;整理&#xff09;。定义在源代码文件 &#xff1a; https://android.googlesource.com/platform/frameworks/base//master/servic…

内网渗透+非局域网下远程桌面连接(借助工具ChmlFrp)

想要通过互联网访问另一台电脑&#xff1f; 家里或实验室有一台主机不方便携带&#xff0c;但是想访问其中的资源该怎么办&#xff1f; 正常情况下大家知道我们想要访问一台设备我们需要知道他的公网ip才可以进行访问&#xff08;访问某台服务器&#xff09;&#xff0c;某个网…

SpringCloud整合Gateway结合Nacos

目录 一、引入依赖 二、开启两个测试项目 2.1 order service ​编辑 2.2 user service 三、gateway项目 3.1 新建一个bootstrap.yml文件 3.2 将我们的的网关配置写道nacos里的配置里 3.3 测试&#xff1a;看能够根据网关路由到两个测试的项目 四、 优化 4.1 将项目打包…

Python中cv2 (OpenCV, opencv-python)库的安装、使用方法demo最新详细教程

&#x1f42f; Python中cv2 (OpenCV, opencv-python)库的安装、使用方法demo最新详细教程 &#x1f4f8; 文章目录 &#x1f42f; Python中cv2 (OpenCV, opencv-python)库的安装、使用方法demo最新详细教程 &#x1f4f8;摘要引言正文&#x1f4d8; OpenCV库概述&#x1f680; …

uni-app - 使用地图功能打包安卓apk的完美流程以及重要的注意事项(带您一次打包成功)

在移动应用开发中&#xff0c;地图功能是一个非常常见且实用的功能&#xff0c;可以帮助用户快速定位并浏览周边信息。而在uni-app开发中&#xff0c;使用地图功能也是一项必备技能。本文将介绍uni-app使用地图功能打包安卓apk的注意事项&#xff0c;帮助开发者顺利完成地图功能…

【Java】图书管理系统 介绍与实现

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持&#xff01; 1.介绍 图书馆作为知识的殿堂和学术的中心&#xff0c;其管理系统不仅是图书馆管理的必备工具&#xff0c;更是为用户提供优质、高效服务的重要保障&#xff0c;促进了知识的传播和学术的发展。随着…

nuxt3使用记录五:禁用莫名其妙的Tailwind CSS(html文件大大减小)

发现这个问题是因为&#xff0c;今天我突然很好奇&#xff0c;我发现之前构建的自动产生的200.html和404.html足足290k&#xff0c;怎么这么大呢&#xff1f;不是很占用我带宽&#xff1f; 一个啥东西都没有的静态页面&#xff0c;凭啥这么大&#xff01;所以我就想着手动把他…