简介:
Webbech能测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况.webBech的标准测试可以向我们展示服务器的两项 内容:每秒钟相应请求数和每秒钟传输数据量.webbench不但能具有便准静态页面的测试能力,还能对动态页面(ASP,PHP,JAVA,CGI)进 行测试的能力.还有就是他支持对含有SSL的安全网站例如电子商务网站进行静态或动态的性能测试.
×××××××××××××××××××××××××吐槽,可忽略××××××××××××××××××××××
好吧 , 我承认好高端,但整个代码也就几百行,还是算上注释呀,看完之后,完全没有什么动态网页测试,SSL 安全网站测试什么选项呀!!!!
,只有选择http协议的请求头选项呀,什么GET,HEAD,之类的
×××××××××××××××××××××××××××××××××××××××××××××××××××××
了解代码,你先得了解它的业务流程
难点一:获取web服务器信息
解决这个问题,首先你的了解你要测试什么? 你要测试的是一个web服务器应对大量请求的能力,就是所说的压力测试。你要做的是同时构造大量的请求,达到测试目的。
请求是由 URL 地址连接 指示的,你要明白URL 地址连接由什么组成,你需要从其中获取那些必要的信息构成请求。url的一般模式为
http://myname:mypass@www.vimer.cn:80/mydir/myfile.html?myvar=myvalue#myfrag
URI部分 |
意义 |
http |
协议名称 |
myname |
用户名(可选) |
mypass |
密码(可选) |
主机网络地址 |
|
80 |
端口号(可选) |
/mydir/myfile.html |
资源路径 |
myvar=myvalue |
查询字符串(可选) |
myfrag |
锚点(可选) |
要从url 提取 host 和 request ,host是主机网络地址,reques 是利用http请求头和资源路径构成的一个http协议请求,web服务器会处理这个请求并且返回资源,一个例子:
输入: http://www.vimer.cn/2010/02/%e7%ae%80%e6%98%8ehttp%e5%8d%8f%e8%ae%ae.html
host www.vimer.cn
request GET /2010/02/%e7%ae%80%e6%98%8ehttp%e5%8d%8f%e8%ae%ae.html HTTP/1.0
如果你纵览了代码,可以说60%的功能都用来进行字符串操作,来获得 host 和 request 不无论是mian函数还build_request 都是来实现这个功能的。具体的细节实现可以参考代码注释,注意一下,使用了大量的字符串函数,随时要准备man一下。
难点二:如何测评,依据是什么
测试就的有一个标准,webbench的标准是成功使用stock建立的http链接,benchwork函数做的就是这样一项工作。webbench使用的是多进程操作,
它选用了通道作为parent和childern的联系方式,来告知parent,child成功或失败建立了几个连接,传送的总的字节数是多少。在博文的最后有一个benchwork函数的流程图,有兴趣的可以看一下
代码
webbench.c
1 /* 2 * (C) Radim Kolar 1997-2004 3 * This is free software, see GNU Public License version 2 for 4 * details. 5 * 6 * Simple forking WWW Server benchmark: 7 * 8 * Usage: 9 * webbench --help 10 * 11 * Return codes: 12 * 0 - sucess 13 * 1 - benchmark failed (server is not on-line) 14 * 2 - bad param 15 * 3 - internal error, fork failed 16 * 17 */ 18 #include "socket.c" 19 #include <unistd.h> 20 #include <sys/param.h> //描述系统参数 21 #include <rpc/types.h> 22 #include <getopt.h>//参数分析 23 #include <strings.h> 24 #include <time.h> 25 #include <signal.h>//信号处理 26 27 /* values */ 28 volatile int timerexpired=0; 29 /* volatile 30 * 提示编译器所定义的变量随时可能改变,因此编译后的程序每次需要存储或是i 31 * 读取该变量的时候,都会直接从变量地址读取数据。 32 * 之所以要这样做,是因为编译器会对代码的读取和存储进行优化,可能暂时使用 33 * 寄存器的值。 34 * */ 35 int speed=0; 36 int failed=0; 37 int bytes=0; 38 /* globals */ 39 int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */ 40 /* Allow: GET, HEAD, OPTIONS, TRACE */ 41 #define METHOD_GET 0 42 #define METHOD_HEAD 1 43 #define METHOD_OPTIONS 2 44 #define METHOD_TRACE 3 45 #define PROGRAM_VERSION "1.5" 46 int method=METHOD_GET; 47 int clients=1;/* 测试进程数,默认1:w*/ 48 int force=0;/* 等待服务器返回标志 ,默认为等待返回 0 */ 49 int force_reload=0; 50 int proxyport=80;/* 服务器端口号,http协议默认为80端口*/ 51 char *proxyhost=NULL;//代理服务器 52 int benchtime=30;/* 运行时间,默认为30 */ 53 /* internal */ 54 int mypipe[2]; /* 通道 */ 55 char host[MAXHOSTNAMELEN];/* 域名 */ 56 #define REQUEST_SIZE 2048 57 char request[REQUEST_SIZE];/* http 请求头 */ 58 59 static const struct option long_options[]= 60 { 61 {"force",no_argument,&force,1}, 62 {"reload",no_argument,&force_reload,1}, 63 {"time",required_argument,NULL,'t'}, 64 {"help",no_argument,NULL,'?'}, 65 {"http09",no_argument,NULL,'9'}, 66 {"http10",no_argument,NULL,'1'}, 67 {"http11",no_argument,NULL,'2'}, 68 {"get",no_argument,&method,METHOD_GET}, 69 {"head",no_argument,&method,METHOD_HEAD}, 70 {"options",no_argument,&method,METHOD_OPTIONS}, 71 {"trace",no_argument,&method,METHOD_TRACE}, 72 {"version",no_argument,NULL,'V'}, 73 {"proxy",required_argument,NULL,'p'}, 74 {"clients",required_argument,NULL,'c'}, 75 {NULL,0,NULL,0} 76 }; 77 /* 静态函数 78 * 特性: 79 * 1.周期:整个程序,范围:本文件 80 * 2.使用static作为前缀,仅可以本文件函数调用, 81 * 不能被同一程序的其他文件调用 82 * 3.可以在不同文件里使用相同的函数名,不用担心冲突 83 * */ 84 /* prototypes */ 85 static void benchcore(const char* host,const int port, const char *request); 86 /* 测试 host 的连接 功能函数 */ 87 static int bench(void); 88 /* 测试 host 的前期准备 和 多进程操作与同行 */ 89 static void build_request(const char *url); 90 /* 解析 request */ 91 92 static void alarm_handler(int signal) 93 /* 和sig 和signaction 构成一个时钟 */ 94 { 95 timerexpired=1; 96 } 97 98 static void usage(void) 99 /* 帮助 */ 100 { 101 fprintf(stderr, 102 "webbench [option]... URL " 103 " -f|--force Don't wait for reply from server. " 104 " -r|--reload Send reload request - Pragma: no-cache. " 105 " -t|--time <sec> Run benchmark for <sec> seconds. Default 30. " 106 " -p|--proxy <server:port> Use proxy server for request. " 107 " -c|--clients <n> Run <n> HTTP clients at once. Default one. " 108 " -9|--http09 Use HTTP/0.9 style requests. " 109 " -1|--http10 Use HTTP/1.0 protocol. " 110 " -2|--http11 Use HTTP/1.1 protocol. " 111 " --get Use GET request method. " 112 " --head Use HEAD request method. " 113 " --options Use OPTIONS request method. " 114 " --trace Use TRACE request method. " 115 " -?|-h|--help This information. " 116 " -V|--version Display program version. " 117 ); 118 }; 119 int main(int argc, char *argv[]) 120 { 121 int opt=0; 122 int options_index=0; 123 char *tmp=NULL; 124 125 if(argc==1) 126 { 127 usage(); 128 return 2; 129 } 130 131 while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF ) 132 /* 使用getopt 函数 获取分析命令,对一些参数进行设置 */ 133 { 134 switch(opt) 135 { 136 case 0 : break; 137 case 'f': force=1;break;//Don't wait for reply from server 138 case 'r': force_reload=1;break;//Send reload request - Pragma: no-cache 139 case '9': http10=0;break; 140 case '1': http10=1;break; 141 case '2': http10=2;break; 142 case 'V': printf(PROGRAM_VERSION" ");exit(0); 143 case 't': benchtime=atoi(optarg);break;//optarg[ getopt的全局变量 ] : 指向当前选项参数的指针 144 case 'p': 145 /* proxy server parsing server:port */ 146 tmp=strrchr(optarg,':'); 147 /* char * strrchr(const char * s,int c ) 148 * 返回 字符c 在字符串s末次出现的位置【返回值指向的是'c' 149 * */ 150 /* 返回的是端口号 151 * */ 152 proxyhost=optarg; 153 if(tmp==NULL) 154 { 155 break; 156 } 157 if(tmp==optarg) 158 { 159 fprintf(stderr,"Error in option --proxy %s: Missing hostname. ",optarg); 160 return 2; 161 }//只有 :port 162 if(tmp==optarg+strlen(optarg)-1) 163 { 164 fprintf(stderr,"Error in option --proxy %s Port number is missing. ",optarg); 165 return 2; 166 }//只有 server: 167 *tmp='