- 后端
- Web框架
- 网络
【免费下载链接】WebServer
A C++ High Performance Web Server
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),整体工作流如下:
- 连通性预检:先
Socket()连接一次目标,失败则打印 "Connect to server failed. Aborting benchmark." 并返回退出码 1(WebBench/webbench.c)。 - 创建结果管道:
pipe(mypipe)建立父子进程间的数据传输通道(WebBench/webbench.c)。 - 批量 fork 客户端:循环
clients次调用fork()。每个子进程sleep(1)后进入压测循环,父进程继续 fork 出下一个子进程,最终形成 1 个父进程 + N 个压测子进程(WebBench/webbench.c)。这也是"最多 3 万并发"的实现基础——每个子进程就是一个独立模拟客户端。 - 子进程压测:每个子进程调用
benchcore(),先通过sigaction注册 SIGALRM 处理函数并alarm(benchtime)设定时长上限,然后进入请求循环(WebBench/webbench.c)。 - 结果回传与汇总:子进程结束时将
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 转换为实际发送的请求报文,核心步骤:
- 合法性校验:必须有
://、必须以http://开头、长度 ≤ 1500、主机名后必须以/结尾; - 主机与端口拆分:非代理模式下从
://之后解析主机名与端口(:出现在/之前视为端口),构造Host: host头; - 请求行拼装:
方法 + 路径(或完整 URL) + HTTP/x.y+\r\n; - 请求头拼装:HTTP/1.0 起附加
User-Agent: WebBench 1.5;非代理模式附加Host;代理 +-r附加Pragma: no-cache;HTTP/1.1 附加Connection: close/Keep-Alive; - 结尾空行:HTTP/0.9 以上以
\r\n结束报文。
拼装完成后程序会先打印出待发送的完整请求报文(\nRequest:\n%s\n),压测前可据此确认请求头是否符合预期。
结合本仓库 WebServer 的实战压测指引
将 WebBench 与本仓库的 C++ WebServer 搭配使用时,推荐如下流程:
- 启动服务器:参考 Main.cpp 与 config.h 配置端口(默认 80)与线程池参数,编译运行 WebServer;
- 准备压测 URL:服务器需提供可访问的资源路径(如仓库 old_version 中的 index.html 或自行编写的响应路径),URL 必须以
/结尾; - 小规模冒烟:先用
webbench -c 10 -t 5 http://127.0.0.1:80/验证连通性与参数正确性,观察输出的Request:报文是否符合预期; - 逐步加压:依次提升
-c(并发数)与-t(时长),对比 Speed 与 bytes/sec 的变化,观察服务器的 QPS 吞吐与稳定性; - 对比保活与非保活:分别用
-2(默认Connection: close)与-2 -k(Keep-Alive)压测,评估长连接复用对吞吐的影响,这正对应本仓库对 WebBench 的 Keep-Alive 增强能力; - 排查失败计数:若
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
相关推荐
exVim开发环境搭建终极指南:如何用exVim开发exVim项目
exVim开发环境搭建终极指南:如何用exVim开发exVim项目 exVim是一款强大的Vim定制化开发环境,它将Vim转变为优秀的编程IDE。本文将为您提供
终极指南:如何用WebBench轻松实现3万并发连接的网站负载测试
终极指南:如何用WebBench轻松实现3万并发连接的网站负载测试 WebBench是一款轻量级但功能强大的网站压测工具,由Radim Kolar在1997年开
运维WebServer 压测实战:基于 Webbench 的短连接/长连接 QPS 对比测试与性能改进分析
WebServer 压测实战:基于 Webbench 的短连接/长连接 QPS 对比测试与性能改进分析 本文以开源仓库 we/WebServer(C++11 编
后端Web框架网络
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考