webbench简介
webbench由C语言写成的用于网站压力测试的一个非常简单的工具,它最多可以模拟30000个并发连接去进行测试。
webbench的安装和使用可以自行百度,也可以过下这篇文章。
webbench执行流程
命令行解析 --> 构建HTTP请求包 --> 创建指定数量的工作进程 --> 每个工作进程对测试网站在测试时间内持续发送请求/接收响应
具体分析
1. 命令行解析。
这里主要用到了getopt库。getopt库是C中常用的命令行解析库,具有如下一些常用的全局变量、结构体以及函数。
/* 常用全局变量 */ extern char* optarg; // 指向获取的option extern int optind; // 已经解析过的option的个数 extern int opterr; // 错误码 extern int optopt;
/* 结构体:解析option时主要的结构体,用以指明有哪些指定options */ struct option { const char* name; int has_arg; int* flag; int val; }; /* has_arg的几个宏 */ #define no_argument 0 #define require_argument 1 #define optional_argument 2
/* 常用的几个函数 */ int getopt(); int getopt_long(int __argc, char* const* __argv, const char* __shortopts, const struct option* __longopts, int* __longind); int getopt_long_only(int __argc, char* const* __argv, const char* __shortopts, const struct option* __longopts, int* __longind);
2. 构建HTTP请求包。
代码调用了build_request函数对HTTP请求包进行了构建。常见的HTTP请求包构建规则:
请求方法 URL 协议版本 \r\n
头部字段名: 值 \r\n
....
头部字段名: 值 \r\n
\r\n
\r\n
请求数据
请求方法:GET, POST, HEAD, PUT, DELETE, TRACE, CONNECT, OPTIONS
协议版本:HTTP/1.0 HTTP/1.1
头部: User-agent, Host, Pragma, Connection等等
3. 使用fork创建指定数量的工作进程,用pipe让主进程和工作进程建立通信,以便于主进程收集子进程的测试信息。
/* 使用fork创建多进程代码片段 */ static int bench(void) { ... for (i = 0; i < clients; i++) { pid = fork(); if (pid <= 0) // 如果是子进程或者fork失败了,退出这个循环 { sleep(1); break; } } ... }
/* fork 函数声明 */ #include <unistd.h> #include <sys/types.h> pid_t fork(void); // pid_t 在 sys/types.h 中定义 /* pipe 函数声明 */ #include <unistd.h> int pipe(int pipefd[2]); /* fdopen 函数声明 */ #include <stdio.h> FILE *fdopen(int fd, const char *mode); // 打开 pipe 文件
4. 每个进程模拟一个客户端,创建socket并连接测试web,用alarm定时测试时长,在这个时间段里,客户端持续向web请求并接收响应。
这里有几点要注意:
a) 在客户端的socket需要两步完成对web的连接:创建一个socket(使用socket()函数);连接web(使用connect()函数)。
b) alarm定时时长,输入的参数只能是秒数。当定时时间到了的时候,系统会发送一个SIGALRM信号给alarm所在的进程,所以在调用alarm之前,需要注册一个信号函数sigaction或signal(代码中使用了sigaction),将SIGALRM与回调函数绑定,当系统发送SIGALRM,会调用相应的回调函数(代码中使用了alarm_handler)进行处理。
上面几个函数的声明如下
/* socket, connect 函数声明 */ #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); /* alarm 函数声明 */ #include <unistd.h> unsigned int alarm(unsigned int seconds); /* sigaction 函数声明 */ #include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigation *oldact); struct sigaction { void (*sa_handler) (int); void (*sa_sigaction) (int, siginfo_t*, void*); sigset_t sa_mask; int sa_flag; void (*sa_restorer) (void); };
完!
2018-03-21 23:39:46