高并发HTTP服务器项目:性能与功能性测试汇总

news2024/9/25 9:34:59

负载测试

测试环境说明

  • 云服务器:2核2G 2M Linux
  • 服务端和客户端环境:同在上述服务器中运行
  • 测试工具
    • wrk 模拟高并发请求
    • htop检测CPU与内存使用情况

低负载压测:百万请求测试,2线程,100并发,1000s(16分钟)测试 

 

 ​​​​​​

  低负载压测:2个线程,100并发量,30s测试

 

 低负载压测:2个线程,100并发量,600s测试

 

 

中负载压测: 12线程,并发6000,3600秒测试

 

 

 高负载压测: 

功能性测试

项目的核心在于构建一个快速构建高性能服务器的组件,完成该组件的构建后,搭建了一个HTTP服务器。该块测试内容即是使用该组件,搭建HTTP服务器是否可以正常工作。

测试1】客户端与服务器之间的长连接(keep-live)功能

  • 测试思路
    • 创建一个长连接请求,并设计一个接收数据的缓冲区
    • 循环执行向服务器发送长连接的请求,每等待三秒接收影响并打印数据
    • 测试客户端和服务器之间长连接是否可以正常保持和超时时间处理的情况
    • 测试文件中添加try-catch捕捉异常,以及日志记录
  • 截图说明(服务端+客户端)
  • 测试源码

void logMessage(const std::string& message) {
    std::cout << message << std::endl;
}

int main() {
    try {
        Socket cli_sock;
        if (!cli_sock.CreateClient(8085, "127.0.0.1")) {
            throw std::runtime_error("Failed to create client socket");
        }
        std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";

        while (true) {
            auto start_time = std::chrono::high_resolution_clock::now();
            if (cli_sock.Send(req.c_str(), req.size()) == -1) {
                throw std::runtime_error("Failed to send request");
            }

            char buf[1024] = {0};
            if (!cli_sock.Recv(buf, 1023)) {
                throw std::runtime_error("Failed to receive response");
            }

            auto end_time = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double> elapsed = end_time - start_time;

            logMessage("Received: " + std::string(buf));
            logMessage("Response time: " + std::to_string(elapsed.count()) + " seconds");

            std::this_thread::sleep_for(std::chrono::seconds(3));
        }

        cli_sock.Close();
    } catch (const std::exception& e) {
        logMessage("Error: " + std::string(e.what()));
        return 1;
    }

    return 0;
}

【测试2】测试客户端和服务端之间的超时连接问题

  • 测试思路
    • 客户端会发送一次数据后进入休眠,检查服务器是否会在客户端没有后续活动的时候,关闭该超时连接 

 

void logMessage(const std::string& message) {
    std::cout << message << std::endl;
}

int main() {
    try {
        Socket cli_sock;
        if (!cli_sock.CreateClient(8085, "127.0.0.1")) {
            throw std::runtime_error("Failed to create client socket");
        }
        std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";
        
        for (int i = 0; i < 5; ++i) { // 进行5次请求测试
            auto start_time = std::chrono::high_resolution_clock::now();
            if (cli_sock.Send(req.c_str(), req.size()) == -1) {
                throw std::runtime_error("Failed to send request");
            }

            char buf[1024] = {0};
            if (!cli_sock.Recv(buf, 1023)) {
                throw std::runtime_error("Failed to receive response");
            }

            auto end_time = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double> elapsed = end_time - start_time;

            logMessage("Received: " + std::string(buf));
            logMessage("Response time: " + std::to_string(elapsed.count()) + " seconds");

            std::this_thread::sleep_for(std::chrono::seconds(15)); // 等待15秒
        }

        cli_sock.Close();
    } catch (const std::exception& e) {
        logMessage("Error: " + std::string(e.what()));
        return 1;
    }

    return 0;
}

【测试3】测试客户端本来声明要给服务端发送1024数据,但是实际数据不足1024字节情况的处理情况

  • 测试思路
    • 分开发送请求头和正文:模拟实际网络情况中网络分包的问题,验证服务器的反应 

void logMessage(const std::string& message) {
    std::cout << message << std::endl;
}

int main() {
    try {
        Socket cli_sock;
        if (!cli_sock.CreateClient(8085, "127.0.0.1")) {
            throw std::runtime_error("Failed to create client socket");
        }

        // 请求头,声明内容长度为100字节
        std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 100\r\n\r\n";
        std::string body = "bitejiuyeke"; // 实际正文只有11字节

        for (int i = 0; i < 3; ++i) { // 测试3次
            // 发送请求头
            if (cli_sock.Send(req.c_str(), req.size()) == -1) {
                throw std::runtime_error("Failed to send request header");
            }
            // 发送正文
            if (cli_sock.Send(body.c_str(), body.size()) == -1) {
                throw std::runtime_error("Failed to send request body");
            }

            char buf[1024] = {0};
            if (!cli_sock.Recv(buf, 1023)) {
                throw std::runtime_error("Failed to receive response");
            }

            logMessage("Received: " + std::string(buf));
            std::this_thread::sleep_for(std::chrono::seconds(3)); // 等待3秒
        }

        cli_sock.Close();
    } catch (const std::exception& e) {
        logMessage("Error: " + std::string(e.what()));
        return 1;
    }

    return 0;
}

 【测试4】测试服务器在处理业务超时的情况,重点测试服务器处理一个业务请求耗时过长的时候,导致其他连接超时并可能引起程序崩溃的问题

  • 测试逻辑
    • 创建多个子进程
    • 每个子进程都创建一个客户端连接到服务器
    • 子进程无限循环的发送请求和接收响应,然后输出响应内容
  • 服务器设计说明
    • 可能出现的问题:服务器处理任务时花费大量时间,可能会导致其他连接因为等待时间过长,然后其连接释放了
      • 问题举例:例如多个排队的文件描述符,全部都已经到达就绪状态,在处理首个文件描述符的时候,花费了大量时间,如果后续连接是通信连接描述符则不影响,如果后面排队的描述符中有定时器文件描述符,该定时器触发的时候,就会引起连环效应,将后面的文件描述符都释放
      • 解决:处理超时连接的时候,释放连接的操作不直接进行,而是将释放压入到任务池中,等到该超时事件处理完成后,再去释放超时连接

void logMessage(const std::string& message) {
    std::cout << message << std::endl;
}

void signalHandler(int signum) {
    logMessage("Interrupt signal (" + std::to_string(signum) + ") received.");
    // Cleanup and close up stuff here
    exit(signum);
}

int main() {
    signal(SIGCHLD, SIG_IGN); // 忽略子进程退出信号

    for (int i = 0; i < 10; i++) {
        pid_t pid = fork();
        if (pid < 0) {
            logMessage("FORK ERROR");
            return -1;
        } else if (pid == 0) {
            try {
                Socket cli_sock;
                if (!cli_sock.CreateClient(8085, "127.0.0.1")) {
                    throw std::runtime_error("Failed to create client socket");
                }
                std::string req = "GET /hello HTTP/1.1\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";

                while (true) {
                    auto start_time = std::chrono::high_resolution_clock::now();

                    if (cli_sock.Send(req.c_str(), req.size()) == -1) {
                        throw std::runtime_error("Failed to send request");
                    }

                    char buf[1024] = {0};
                    if (!cli_sock.Recv(buf, 1023)) {
                        throw std::runtime_error("Failed to receive response");
                    }

                    auto end_time = std::chrono::high_resolution_clock::now();
                    std::chrono::duration<double> elapsed = end_time - start_time;

                    logMessage("Received: " + std::string(buf));
                    logMessage("Response time: " + std::to_string(elapsed.count()) + " seconds");
                }

                cli_sock.Close();
            } catch (const std::exception& e) {
                logMessage("Error: " + std::string(e.what()));
            }
            exit(0);
        }
    }

    signal(SIGINT, signalHandler); // 捕捉 SIGINT 信号,进行清理
    while (true) {
        sleep(1); // 主进程保持运行
    }

    return 0;
}

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

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

相关文章

C++ 几何算法 - 求两条直线交点

一:算法介绍 1. 首先定义两条直线方程: 2. 解方程,求出x, y坐标 3. 如果x分母的行列式等于0, 说明两条直线平行或方向相反 4. 如果x,y分母的行列式都等于0,说明两条线重叠 二:代码实现: #include <cmath> #include <iostream>class Point2D { public:doubl…

Dubbo框架实现RPC远程调用包括nacos的配置和初始化

项目背景介绍 这个技术我是直接在项目中运用并且学习的&#xff0c;所以我写笔记最优先的角度就是从项目背景出发 继上一次API网关完成了这个实现用户调用一次接口之后让接口次数增多的操作之后&#xff0c;又迎来了新的问题。 就是我们在调用接口的时候需要对用户进行校验&…

关于地址的级联选择器

相信大家在项目中经常要做关于地址的级联选择器&#xff1a;效果如下图 在常见的组件库&#xff0c;例如element-ui/element-plus等中就有关于级联选择器的使用&#xff0c;但该组件并没有封装好的关于中国省市区甚至更详细的关于地址的级联选择器&#xff0c;因此我尝试在网络…

Excel中的数据筛选利器:COUNTIF函数深度解析与应用实战

文章目录 前言一、COUNTIF基础应用二、常见用法1.基本条件计数2.使用通配符进行模糊匹配3.引用单元格中的值作为条件4.多条件计数&#xff08;使用COUNTIFS&#xff09;5.重复值查找与去重6.结合其他函数使用 前言 Excel中的COUNTIF函数是一个极为强大且灵活的工具&#xff0c;…

【MongoDB 】MongoDB 介绍及应用,设计到4个案例

MongoDB 介绍概述 基础概念 MongoDB 是非关系型数据库&#xff0c;也就是nosql&#xff0c;存储json数据格式会非常灵活&#xff0c;要比数据库mysql/MariaDB更好&#xff0c;同时也能为mysql/MariaDB分摊一部分的流量压力。 对于经常读写的数据他会存入内存&#xff0c;如此…

STL中的list以及简单实现

STL的list的底层结构其实就是带头双向循环双向链表 带头双向循环双向链表又简单又好用&#xff0c;效率又高&#xff0c;所以其结构是完美的&#xff08;对于链表而言&#xff09;&#xff1a; 其中一个原因&#xff1a;有哨兵位的头节点&#xff0c;又循环&#xff0c;找尾很…

前端day7-css选择器

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>css</title><!-- 内嵌式CSS --><sty…

Python 为Excel单元格设置填充\背景色 (纯色、渐变、图案)

在使用Excel进行数据处理和分析时&#xff0c;对特定单元格进行背景颜色填充不仅能够提升工作表的视觉吸引力&#xff0c;还能帮助用户快速识别和区分不同类别的数据&#xff0c;增强数据的可读性和理解性。 本文将通过以下三个示例详细介绍如何使用Python在Excel中设置不同的单…

远程连接本地虚拟机失败问题汇总

前言 因为我的 Ubuntu 虚拟机是新装的&#xff0c;并且应该装的是比较纯净的版本&#xff08;纯净是指很多工具都尚未安装&#xff09;&#xff0c;然后在使用远程连接工具 XShell 连接时出现了很多问题&#xff0c;这些都是我之前没遇到过的&#xff08;因为之前主要使用云服…

javax.validation.constraints.NotEmpty 报错

1、问题 javax.validation.constraints.NotEmpty报错2、原因 validation-api版本较低问题 3、解决 升级版本 javax.validation:validation-api 由1.1.0.Final升级至 2.0.1.Final <dependency><groupId>javax.validation</groupId><artifactId>vali…

机房托管服务器说明

机房托管服务器是指将企业或个人的服务器放置到专业数据中心(IDC机房)进行管理和维护&#xff0c;由数据中心提供稳定、安全的运行环境以及网络连接等基础设施支持。rak小编为您整理发布机房托管服务器说明详细内容。 通过托管服务器到专业机房&#xff0c;企业能够享受到高性能…

【Redis 进阶】集群(重点理解流程和原理)

一、基本概念 前面学习的哨兵模式&#xff0c;提高了系统的可用性。但是真正用来存储数据的还是 master 和 slave 节点&#xff0c;所有的数据都需要存储在单个 master 和 slave 节点中。如果数据量很大&#xff0c;接近超出了 master / slave 所在机器的物理内存&#xff0c…

Maxon公司产品将于 2024 年 9 月提高订阅价格?

Maxon公司的用户们最近在Reddit和Core 4D论坛上分享了一张图片&#xff0c;图片内容显示了Maxon公司计划在2024年9月1日对其产品订阅价格进行调整&#xff0c;涉及的产品包括Cinema 4D和ZBrush等。 根据这张图片&#xff0c;Redshift渲染器的月度订阅费用将上涨2.2%&#xff0c…

社交网络的演变:从Facebook到Meta的战略转型

随着科技的飞速发展&#xff0c;社交网络平台正经历着深刻的变革。Facebook的品牌重塑为Meta不仅是名称的更改&#xff0c;更是对未来社交网络模式的全新定义。本文将深入探讨Facebook向Meta转型的背景、战略及其未来影响&#xff0c;剖析这一转型对社交网络的深远影响。 背景与…

UKP3d,AutoPDMS出报表时数值格式如何调整

用户问&#xff0c;支吊架一览表的位移数值不是整数&#xff0c;请问怎么处理呢&#xff1f; 1.在AutoPDMS是修改软件的安装目录下的配置文件&#xff0c;如图&#xff1a; 2.在UKP3d里修改报表元件&#xff0c;如图&#xff1a;

嵌入式day21

fileno 获得一个文件流指针中的文件描述符 FILE *fp -> int fd stream 文件流指针 返回值&#xff1a; 成功 返回文件描述符 失败 返回-1 关文件一般关封装度高的 fdopen 将文件描述符转化为文件流指针 int fd -> FILE *fp fd : 已经打开的文件描述符 mode &quo…

Unity检测鼠标进入、离开UI

Unity检测鼠标进入、离开UI检测 引用命名空间 UnityEngine.EventSystems IPointerEnterHandler&#xff1a;进入 IPointerExitHandler&#xff1a;离开 注意&#xff1a;Image需开启RaycastTarget using UnityEngine; using UnityEngine.EventSystems; public class IPointe…

8.7-主从数据库的配置+mysql的增删改查

一、mysql环境的配置 1.环境准备 &#xff08;1&#xff09;主数据库 #关闭防火墙 [rootmaster ~]# systemctl stop firewalld#关闭selinux [rootmaster ~]# setenforce 0#下载lrzsz工具 [rootmaster ~]# yum -y install lrzsz#安装rsync [rootmaster ~]# yum -y install rs…

如何高效利用阿里云Docker镜像仓库管理您的容器镜像

文章目录 前言一、Docker镜像仓库1.公共仓库2.私有仓库 二、开通阿里云Docker镜像仓库ACR1.创建阿里云账号并开通容器镜像服务2.创建命名空间与镜像仓库 三、如何使用镜像仓库ACR1.登录阿里云Docker Registry2.推送镜像到阿里云私有镜像仓库3.从阿里云私有镜像仓库拉取镜像 总结…

CAN直接网络管理(20240805)

长安CAN网络管理规范 个人理解&#xff1a;管理CAN网络中各NM节点的工作模式&#xff08;状态&#xff09;&#xff1b; 1.术语定义 &#x1f449;节点地址&#xff1a;用于唯一标识网络中每个节点的单字节数字&#xff0c;取值范围是 0x00~0xFF。&#x1f449;状态迁移&#x…