WebBench 源码解析
一、前言
WebBench 作为一款网站性能测试工具,其源码蕴含着丰富的技术细节和逻辑流程。本文将深入剖析其安装编译过程以及关键函数的核心逻辑。
二、安装编译
1. 克隆代码到本地仓库
git clone https://github.com/EZLippi/WebBench.git
2. 编译
sudo make
踩坑及解决方法:
踩坑 1:
解决方法:
将 webbench.c
中的 #include <rpc/types.h>
改为 #include <sys/types.h>
,从而解决报错 。
踩坑 2:
解决方法:安装依赖 sudo apt-get install universal-ctags
编译通过后安装到本地
sudo make install PREFIX=your_path_to_webbench //your_path_to_webbench 自己的安装目录下面
验证是否安装成功:
在终端中直接输入 webbench
命令
到此,编译安装完毕!!!
三、源码解析
(一)main
函数
main
函数承担着处理命令行参数、初始化相关变量以及调度后续操作流程的重要职责。
- 首先,它会对命令行参数的数量进行校验。若仅输入一个参数,会调用
usage
函数并返回 2 ,提示用户输入有误。 - 接着,通过
getopt_long
函数来精细地解析命令行参数,并依据不同的参数值对相应的变量进行设置,比如设定特定的标志位、转换并设定变量的值等。 - 然后,检查用户是否提供了有效的 URL 。若未提供,会打印错误信息,调用
usage
函数,并返回 2 ,以表明输入不完整。 - 此外,还会对一些变量进行默认值的处理。例如,当
clients
为 0 时,将其设定为 1 ;当benchtime
为 0 时,将其设定为 30 。 - 随后,调用
build_request
函数来构建请求。 - 最后,打印运行相关的信息,并调用
bench
函数来开展性能测试,同时返回bench
函数的返回值。
在 switch
语句中:
case 'f'
:将force
标志设置为 1 ,启用特定功能。case 'r'
:将force_reload
标志设置为 1 。case '9'
:将http10
设置为 0 ,可能对应特定的 HTTP 版本选择。case '1'
:将http10
设置为 1 。case '2'
:将http10
设置为 2 。case 'V'
:打印程序的版本信息并退出程序。case 't'
:将benchtime
变量的值通过atoi
函数对optarg
进行转换后设定。case 'p'
:细致地处理代理服务器的参数,解析出主机名和端口。
(二)build_request
函数
build_request
函数的核心任务是依据输入的 URL 和一系列设定条件,精心构建出完整的 HTTP 请求字符串,同时进行必要的错误校验和处理操作。
- 函数起始处,定义了一些局部变量,并运用
memset
函数将host
和request
缓冲区清零。 - 接着,基于不同的条件判断来调整
http10
的值。 - 然后,依据请求方法设定
request
字符串的起始部分,例如GET
、HEAD
等。 - 此后,对输入的
url
展开一系列严格的检查和处理操作,涵盖检查是否存在特定的协议标识、长度是否合规、语法是否正确等。 - 明确协议/主机的分隔位置。
- 依照是否设置了代理主机来分别处理
host
并构建request
字符串。 - 依据
http10
的值添加相应的协议版本信息到request
中。 - 有可能添加一些额外的头部信息,例如用户代理、主机、强制不缓存等。
- 最终,打印构建完成的请求字符串。
(三)bench
函数
bench
函数主要负责创建子进程、与子进程进行通信并汇总测试结果。
- 首先,定义了一些变量,如用于存储子进程返回值的
i
、j
、k
,进程标识符pid
,文件指针f
等。 - 调用
Socket
函数检查目标服务器的可用性,如果连接失败则打印错误信息并返回 1 。 - 使用
pipe
函数创建管道,如果创建失败打印错误并返回 3 。 - 通过循环使用
fork
函数创建指定数量(clients
)的子进程。- 如果
fork
结果小于 0 ,表示创建子进程时出现问题,打印错误信息并返回 3 。 - 如果
fork
结果等于 0 ,表示当前为子进程。- 根据是否有代理主机,调用
benchcore
函数进行核心测试工作。 - 使用
fdopen
将管道的写端转换为文件指针,并将测试结果(速度、失败次数、字节数)写入管道。 - 关闭文件指针并返回 0 。
- 根据是否有代理主机,调用
- 如果
fork
结果大于 0 ,表示当前为父进程。- 使用
fdopen
将管道的读端转换为文件指针。 - 初始化速度、失败次数和字节数等统计变量。
- 进入一个循环,从管道读取子进程的测试结果,并更新统计变量。
- 如果读取到的数据不完整或所有子进程都已结束,退出循环。
- 关闭文件指针并打印测试结果,包括速度、字节数、成功和失败的请求数。
- 使用
- 如果
- 最后,返回一个整数值。
(四)benchcore
函数
benchcore
函数在子进程中执行与服务器的交互和测试工作。
- 定义了一些变量,包括请求长度
rlen
、缓冲区buf
、套接字描述符s
等。 - 设置信号处理函数
sa
来处理定时信号。 - 使用
alarm
函数设置定时时间。 - 进入一个无限循环。
- 如果定时时间已到,根据失败次数进行调整并返回。
- 使用
Socket
函数创建套接字连接服务器,如果失败则增加失败次数并继续下一次循环。 - 向套接字写入请求,如果写入长度不一致则增加失败次数并关闭套接字继续下一次循环。
- 根据
http10
的值进行相应处理,如果需要关闭套接字但失败则增加失败次数并继续下一次循环。 - 如果
force
标志为 0 ,从套接字读取数据,如果读取失败则增加失败次数、关闭套接字并跳转到nexttry
标签处重新开始循环。 - 如果读取到的数据长度为 0 则退出内层循环。
- 否则增加字节数统计。
- 如果成功关闭套接字则增加速度统计。
四、总结
main
函数:- 处理命令行参数,进行必要的检查和默认值设置。
- 调用相关函数构建请求和进行性能测试。
build_request
函数:- 构建完整的 HTTP 请求字符串,并进行错误检查。
bench
函数:- 管理子进程的创建和与子进程的通信。
- 汇总子进程的测试结果并输出。
benchcore
函数:- 在子进程中执行与服务器的交互和测试操作。
通过对这些函数的理解,可以更好地掌握 WebBench 的工作原理和内部实现机制,为进一步的使用和优化提供基础。