news 2026/9/26 8:34:10

WebBench 压测工具深度解析:在 C++ WebServer 项目中用 fork 模拟 3 万并发连接

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WebBench 压测工具深度解析:在 C++ WebServer 项目中用 fork 模拟 3 万并发连接
  • 后端
  • Web框架
  • 网络

【免费下载链接】WebServer

A C++ High Performance Web Server

项目地址:https://gitcode.com/gh_mirrors/we/WebServer
点击查看免费下载

WebBench 是一个运行在 Linux 下的轻量级 HTTP 网站压测工具,它通过fork()派生出多个子进程来模拟多个客户端同时访问指定 URL,以评估目标网站在压力下的吞吐能力,理论上最多可模拟 3 万个并发连接。本指南将围绕 WebBench/README.md 展开,完整讲解其安装方式、命令行选项、输出指标含义,并结合 WebBench/webbench.c 与 WebBench/socket.c 源码剖析其 fork 压测模型与请求构造原理,帮助你直接用它对本仓库的 C++ WebServer 进行压测验证。

为什么需要 WebBench:压测场景与适用前提

本仓库 README.md 明确说明,项目使用 Epoll 边沿触发的 IO 多路复用、Reactor 模式与线程池构建了一个高性能 C++ Web Server,而在服务器开发完成后,需要借助压测工具验证其在并发压力下的真实表现。官方对开源 WebBench 进行了针对性改写——增加了 Keep-Alive 选项和测试功能,这正是仓库内 WebBench/ 目录存在的意义。

WebBench 的设计哲学是"简单":它只做一件事——用fork()模拟多个客户端,持续向目标 URL 发送 HTTP 请求并统计结果。它并不追求像 ApacheBench、wrk 那样丰富的功能,而是以极简的代码实现足够真实的并发负载。其 man 手册 WebBench/webbench.1 还特别指出:与依赖select()的压测工具不同,WebBench 使用多进程模拟多用户流量,在 SMP 系统以及select()实现缓慢或有缺陷的系统上表现更好。

需要说明的适用前提:WebBench 是一个压测客户端,运行时需要目标服务器处于可连接状态(可以是本机 WebServer,也可以是任意 HTTP 服务器或可通过 HTTP 代理访问的其他协议服务);它运行在 Linux 平台,构建依赖gcc、make与ctags。

安装与构建:从源码到命令行工具

WebBench 的源码构成非常精简:

  • WebBench/webbench.c:主程序,包含参数解析、请求构造与压测核心逻辑(约 567 行);
  • WebBench/socket.c:网络连接封装(源自 popclient 1.5 的公有领域 UNIX socket 代码,由 Radim Kolar 修改);
  • WebBench/Makefile:构建与安装脚本;
  • WebBench/webbench.1:man 手册页。

依赖项只有ctags(用于生成源码标签文件,见 Makefile 中tags: *.c规则)。安装命令遵循 README 给出的方式:

sudo make && sudo make install PREFIX=your_path_to_webbench

其中PREFIX指定安装前缀,默认值为/usr/local/webbench(见 WebBench/Makefile)。安装过程会执行如下操作(对应 Makefile 的install目标):

  • 将编译好的webbench二进制安装到$(PREFIX)/bin,并软链接到/usr/local/bin/webbench,使其可直接在命令行调用;
  • 将 man 手册 WebBench/webbench.1 安装到$(PREFIX)/man/man1及系统 man 目录,之后可用man webbench查看帮助;
  • 将 WebBench/debian/copyright 与 changelog 安装为文档。

编译细节可在 WebBench/Makefile 中调整:默认CC=gcc,CFLAGS=-Wall -ggdb -W -O(开启警告、调试信息与优化),版本号为 1.5。仓库还附带 Debian 打包支持(WebBench/debian/control、WebBench/debian/rules),可用于生成 deb 包。仓库中已包含编译产物WebBench/webbench,因此也可以直接执行该二进制,或用make重新构建(make clean可清理中间文件)。

命令行选项全解:从 README 参数表到源码实现

README 给出了完整的命令行选项表。下面将该表完整保留,并逐项补充源码层面的行为细节(对应 WebBench/webbench.c 中的long_options定义与 WebBench/webbench.c 的getopt_long解析逻辑):

短参长参数作用
-f--force不需要等待服务器响应(发送请求后立即关闭连接,接近 DoS 攻击行为)
-r--reload发送重新加载请求(附带Pragma: no-cache头)
-t--time <sec>运行多长时间,单位:秒(默认 30 秒)
-p--proxy <server:port>使用代理服务器来发送请求
-c--clients <n>创建多少个客户端,默认 1 个
-k--keep启用 HTTP/1.1 Keep-Alive 连接(本仓库改写的核心新增选项)
-9--http09使用 HTTP/0.9
-1--http10使用 HTTP/1.0 协议(默认)
-2--http11使用 HTTP/1.1 协议
--get使用 GET 请求方法(默认)
--head使用 HEAD 请求方法
--options使用 OPTIONS 请求方法
--trace使用 TRACE 请求方法
-?/-h--help打印帮助信息
-V--version显示版本号(1.5)

各选项的源码行为细节

-f / --force:不等待响应。对应全局变量force。源码中benchcore()在写完请求后跳过read()阶段直接计数(WebBench/webbench.c)。man 手册明确指出该选项"能产生相当不错的 DoS 攻击效果",所以压测线上服务时需谨慎使用。

-r / --reload:强制代理重新加载。对应force_reload。构造请求时仅在设置了代理(proxyhost != NULL)的情况下附加Pragma: no-cache\r\n头(WebBench/webbench.c);不设代理时该选项无实际效果,与 man 手册描述一致。

-t / --time <sec>:压测时长。对应benchtime,默认 30 秒(WebBench/webbench.c),解析后若为 0 会被重置为 30(WebBench/webbench.c)。每个子进程通过alarm(benchtime)设置闹钟,超时后由alarm_handler将timerexpired置 1,压测循环随之退出(WebBench/webbench.c)。

-p / --proxy <server:port>:走代理。使用strrchr从右向左定位最后一个:来拆分server:port(WebBench/webbench.c)。三种边界情况处理:无:则端口保持默认 80;:在开头则报错"Missing hostname";:在结尾则报错"Port number is missing"。启用代理后,请求行直接写入完整 URL(如GET http://... HTTP/1.0),并且不附加Host头。man 手册指出代理模式是访问"HTTP 之外其他协议服务"的唯一途径。

-c / --clients <n>:并发客户端数。对应clients,默认 1,解析后为 0 会被重置为 1(WebBench/webbench.c)。README 宣称最多可模拟 3 万个并发连接,实际以 Linux 系统的fork()能力与进程数上限(如ulimit -u)为约束。

-k / --keep:Keep-Alive(仓库改写新增)。这是本仓库相对上游的重要增强,对应全局布尔变量keep_alive(WebBench/webbench.c),与 README.md 中"对开源测试工具 Webbench 增加了 Keep-Alive 选项和测试功能"的描述吻合。开启后请求头使用Connection: Keep-Alive,否则使用Connection: close(WebBench/webbench.c);且仅在 HTTP/1.1(http10>1)下该头才生效。

-9 / -1 / -2:协议版本。对应http10整型变量:0 表示 HTTP/0.9、1 表示 HTTP/1.0(默认)、2 表示 HTTP/1.1(WebBench/webbench.c)。协议影响请求行与头的构造:HTTP/0.9 只发送"方法 + 路径"(无协议版本、无任何头、无结尾空行);HTTP/1.0 追加HTTP/1.0版本号、User-Agent: WebBench 1.5与Host头;HTTP/1.1 进一步追加Connection头(WebBench/webbench.c)。

--get / --head / --options / --trace:请求方法。对应method枚举(GET=0、HEAD=1、OPTIONS=2、TRACE=3,见 WebBench/webbench.c)。构造请求时方法字符串被写入请求行起始位置。源码还会自动调整协议下限:--head强制 HTTP/1.0 及以上,--options与--trace强制 HTTP/1.1(WebBench/webbench.c),因为这些方法在更低的协议版本中不存在或不合理。

-V / --version:直接打印1.5并退出(WebBench/webbench.c)。README 表格未列出的-v短参在 man 手册中出现,当前源码仅支持-V。

典型压测命令

仓库 WebBench/test.sh 给出了针对本 WebServer 的实测命令(10 秒后手动结束,60 秒、1000 并发、HTTP/1.1、GET):

./bin/webbench -t 60 -c 1000 -2 --get http://127.0.0.1:80/hello

针对本仓库 WebServer 的其他常用场景:

# 压测非保活连接(HTTP/1.1,连接用完即关) webbench -c 100 -t 30 -2 http://127.0.0.1:8888/ # 压测 Keep-Alive 长连接场景(仓库改写新增能力,更贴近真实浏览器行为) webbench -c 100 -t 30 -2 -k http://127.0.0.1:8888/ # 只统计发送速率,不等待响应 webbench -c 1000 -t 10 -f http://127.0.0.1:8888/ # 经代理压测 webbench -c 100 -t 30 -p 127.0.0.1:3128 http://example.com/

注意:WebBench 只直接支持http://前缀的 URL(见 WebBench/webbench.c),且 URL 长度不能超过 1500 字符、必须以/结尾否则报"Invalid URL syntax"(WebBench/webbench.c)。URL 中允许显式携带端口(如http://127.0.0.1:8888/),未指定端口时默认 80(WebBench/webbench.c)。

输出指标解读:Speed、Requests 与失败计数

压测结束后,父进程汇总所有子进程结果并打印(WebBench/webbench.c):

Speed=1800 pages/min, 12345 bytes/sec. Requests: 3000 susceed, 0 failed.

三个核心指标的准确含义:

  • Speed(pages/min,页/分钟):(speed + failed) / (benchtime / 60.0f),即"成功请求 + 失败请求"的总请求数换算成每分钟速率,统计的是请求发送总量而非响应完成量;
  • bytes/sec(字节/秒):bytes / benchtime,所有子进程累计读取到的响应字节数除以压测时长,反映响应吞吐;
  • Requests: susceed, failed:speed为成功完成(写入请求且计数)的次数,failed为失败次数,包括连接建立失败、写入失败、读取失败等(WebBench/webbench.c 中所有failed++分支)。

一个值得注意的实现细节:定时器到期时,若已累计失败计数,源码会做一次"失败校正"(failed--),把闹钟中断本身导致的最后一次未完成请求从失败中剔除(WebBench/webbench.c)。因此压测时间到点时的failed数值可能略小于实际失败次数,解读时应结合日志综合判断。

压测原理剖析:fork 多进程模型与内部工作流

WebBench 的核心是bench()与benchcore()两个函数(WebBench/webbench.c),整体工作流如下:

  1. 连通性预检:先Socket()连接一次目标,失败则打印 "Connect to server failed. Aborting benchmark." 并返回退出码 1(WebBench/webbench.c)。
  2. 创建结果管道:pipe(mypipe)建立父子进程间的数据传输通道(WebBench/webbench.c)。
  3. 批量 fork 客户端:循环clients次调用fork()。每个子进程sleep(1)后进入压测循环,父进程继续 fork 出下一个子进程,最终形成 1 个父进程 + N 个压测子进程(WebBench/webbench.c)。这也是"最多 3 万并发"的实现基础——每个子进程就是一个独立模拟客户端。
  4. 子进程压测:每个子进程调用benchcore(),先通过sigaction注册 SIGALRM 处理函数并alarm(benchtime)设定时长上限,然后进入请求循环(WebBench/webbench.c)。
  5. 结果回传与汇总:子进程结束时将speed failed bytes三个数写入管道;父进程用无缓冲setvbuf的fscanf逐个读取并累加(WebBench/webbench.c)。

两种压测循环:非 Keep-Alive 与 Keep-Alive

benchcore()内部根据keep_alive分支为两种模式(WebBench/webbench.c):

非 Keep-Alive 模式(默认),每次请求都是"连接-发送-读取-关闭":

s = Socket(host, port); // 新建 TCP 连接 write(s, req, rlen); // 发送完整请求 read(s, buf, 1500); // 读取响应(force=0 时) close(s); // 关闭连接 speed++; // 计数一次成功

其中Socket()封装了域名解析(gethostbyname)或点分 IP 直转(inet_addr)、socket()与connect()(WebBench/socket.c)。HTTP/0.9 模式下还会在发送后调用shutdown(s, 1)关闭写方向(WebBench/webbench.c)。

Keep-Alive 模式(仓库新增),先建立一个连接,然后在该连接上循环"写请求-读响应-计数",连接保持不关闭;一旦写入失败才重新连接(WebBench/webbench.c):

s = Socket(host, port); // 建立一次长连接 while (1) { if (timerexpired) ... // 到点退出 write(s, req, rlen); // 复用连接发送 read(s, buf, 1500); // 读取响应 speed++; }

这一模式正是本仓库 README.md 所述"增加 Keep-Alive 选项和测试功能"的具体落地,用于验证 WebServer 对 HTTP 长连接的保持能力(对应仓库主项目中"连接的维护"设计)。注意读取逻辑:非 Keep-Alive 模式下read()返回 0(EOF)即结束本次请求,Keep-Alive 模式下依赖 HTTP 响应自身边界,读取失败才计入失败。

退出码约定

main的返回码约定(WebBench/webbench.c 与 man 手册一致):

退出码含义
0压测成功完成
1压测失败(无法连接服务器)
2命令行参数错误(如缺少 URL、URL 非法、proxy 格式错误)
3内部错误(如 fork 失败、管道创建失败)

请求构造细节:从 URL 到完整 HTTP 报文

build_request()(WebBench/webbench.c)将用户输入的 URL 转换为实际发送的请求报文,核心步骤:

  1. 合法性校验:必须有://、必须以http://开头、长度 ≤ 1500、主机名后必须以/结尾;
  2. 主机与端口拆分:非代理模式下从://之后解析主机名与端口(:出现在/之前视为端口),构造Host: host头;
  3. 请求行拼装:方法 + 路径(或完整 URL) + HTTP/x.y+\r\n;
  4. 请求头拼装:HTTP/1.0 起附加User-Agent: WebBench 1.5;非代理模式附加Host;代理 +-r附加Pragma: no-cache;HTTP/1.1 附加Connection: close/Keep-Alive;
  5. 结尾空行:HTTP/0.9 以上以\r\n结束报文。

拼装完成后程序会先打印出待发送的完整请求报文(\nRequest:\n%s\n),压测前可据此确认请求头是否符合预期。

结合本仓库 WebServer 的实战压测指引

将 WebBench 与本仓库的 C++ WebServer 搭配使用时,推荐如下流程:

  1. 启动服务器:参考 Main.cpp 与 config.h 配置端口(默认 80)与线程池参数,编译运行 WebServer;
  2. 准备压测 URL:服务器需提供可访问的资源路径(如仓库 old_version 中的 index.html 或自行编写的响应路径),URL 必须以/结尾;
  3. 小规模冒烟:先用webbench -c 10 -t 5 http://127.0.0.1:80/验证连通性与参数正确性,观察输出的Request:报文是否符合预期;
  4. 逐步加压:依次提升-c(并发数)与-t(时长),对比 Speed 与 bytes/sec 的变化,观察服务器的 QPS 吞吐与稳定性;
  5. 对比保活与非保活:分别用-2(默认Connection: close)与-2 -k(Keep-Alive)压测,评估长连接复用对吞吐的影响,这正对应本仓库对 WebBench 的 Keep-Alive 增强能力;
  6. 排查失败计数:若failed持续增长,优先检查连接数上限(ulimit -n)、进程数上限(ulimit -u)与服务器端日志(仓库 base/ 提供了异步日志组件),确认是客户端资源限制还是服务器处理瓶颈。

压测时注意:-c达到数万级别会派生大量进程,务必确认系统允许的进程数上限;-f模式接近 DoS 行为,仅适合在受控环境验证极限吞吐。

结语

WebBench 以极简的 fork 多进程模型提供了"最多 3 万并发连接"的 HTTP 压测能力,其全部逻辑集中在 WebBench/webbench.c 与 WebBench/socket.c 两个文件中,易于阅读与二次改造。本仓库的这份副本在原生基础上增加了 Keep-Alive 选项,配合 WebBench/test.sh 中的示例命令,可直接用于对本仓库 C++ WebServer 进行长连接与短连接两种模式的对比压测。理解其参数、指标与退出码约定,是正确解读压测结果、定位服务器性能瓶颈的第一步。

  • 后端
  • Web框架
  • 网络

【免费下载链接】WebServer

A C++ High Performance Web Server

项目地址:https://gitcode.com/gh_mirrors/we/WebServer
点击查看免费下载
上一篇:FF14 ACT辍学插件完整指南:三步快速跳过副本动画的终极方案
下一篇:PyQt-Fluent-Widgets深度解析:现代化桌面应用开发的架构与实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 8:32:50

货拉拉大模型广告文案实践:从场景边界到数据闭环

做营销广告的人应该都有同感&#xff1a;渠道侧对创意素材的消耗速度&#xff0c;早就跑赢了创意团队的生产速度。在我们尝试把大模型用在货拉拉的营销广告场景之前&#xff0c;这个问题在公司内部尤其刺眼——货主端和司机端是两套完全不同的用户体系&#xff0c;货运、搬家、…

作者头像 李华
网站建设 2026/9/26 8:32:11

实测AI Agent独立制作视频:本地部署OpenMontage全流程

前阵子有个朋友问我&#xff1a;AI Agent 到底能不能真的自己做出一条视频&#xff1f;从写脚本、找素材、配音、剪片子到加字幕&#xff0c;整个过程不让人插手&#xff0c;最后直接丢给你一个能发的 MP4。我决定不猜&#xff0c;直接拿一个项目来实测。我选了 OpenMontage 这…

作者头像 李华
网站建设 2026/9/26 8:30:59

问道1.4服务端架设:all.sql数据库导入与MySQL配置优化指南

简介&#xff1a;这份资源是《问道》1.4版本服务端数据库的完整SQL脚本文件包&#xff0c;面向网络游戏爱好者、独立架设私服的站长以及想了解国产回合制游戏后端数据结构的开发者。压缩包内含1个sql文件&#xff0c;整体大小174KB&#xff0c;仅需执行这一份all.sql脚本&#…

作者头像 李华
网站建设 2026/9/26 8:30:33

数据库原理上机实验全攻略:从建表到事务并发的实战指南

简介&#xff1a;北京理工大学计算机学院“数据库原理与设计”课程上机实验完整材料包&#xff0c;面向该课程本科生复习实验内容&#xff0c;也适合备考数据库原理或需要规范练习SQL的开发者。压缩包共12个文件、4.69MB&#xff0c;包含4个SQL脚本、3个JavaScript文件、2个JSO…

作者头像 李华
网站建设 2026/9/26 8:29:34

Kylin V10 SP3服务器部署实战:硬件兼容、U盘安装与生产加固

1. 为什么选Kylin V10 SP3做服务器系统&#xff1f;——从真实运维场景说起我第一次在某省政务云项目里接手Kylin V10 SP3服务器部署&#xff0c;不是因为“国产化替代”这种口号&#xff0c;而是因为客户机房里那台跑了八年、连UEFI固件都打不了补丁的老IBM X3650 M4——它根本…

作者头像 李华