zoukankan      html  css  js  c++  java
  • webbench工具使用和源码分析

    Webbench是有名的网站压力测试工具,它是由Lionbridge公司(http://www.lionbridge.com)开发.它的帮助文件和文档请到:www.webbench.com上查看.

    Webbech能测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况.webBech的标准测试可以向我们展示服务器的两项 内容:每秒钟相应请求数和每秒钟传输数据量.webbench不但能具有便准静态页面的测试能力,还能对动态页面(ASP,PHP,JAVA,CGI)进 行测试的能力.还有就是他支持对含有SSL的安全网站例如电子商务网站进行静态或动态的性能测试.

    下载:

        官方网站:http://home.tiscali.cz/~cz210552/webbench.html

    安装:

        tar zxvf webbench-1.5.tar.gz

        cd webbench-1.5

        make;make install


    使用:

        webbench -c 200 -t 20 http://www.doglover.net/

        其中-c 200 代表200个并发用户进行访问-t 20  即20S,访问的url为http://www.doglover.net/;运行20S之后可以看到如下的结果:


        可以根据打印中的信息来判断网站的抗压情况。另外使用 webbench -help  可以获得更多的使用信息。

    源码分析:
        整个webbench工程一共有两个C文件:socket.c和webbench.c。具体的分析如下:
    socket.c
    1. /* $Id: socket.c 1.1 1995/01/01 07:11:14 cthuang Exp $
    2. *
    3. * This module has been modified by Radim Kolar for OS/2 emx
    4. */
    5. /***********************************************************************
    6. module: socket.c
    7. program: popclient
    8. SCCS ID: @(#)socket.c 1.5 4/1/94
    9. programmer: Virginia Tech Computing Center
    10. compiler: DEC RISC C compiler (Ultrix 4.1)
    11. environment: DEC Ultrix 4.3
    12. description: UNIX sockets code.
    13. ***********************************************************************/
    14. #include <sys/types.h>
    15. #include <sys/socket.h>
    16. #include <fcntl.h>
    17. #include <netinet/in.h>
    18. #include <arpa/inet.h>
    19. #include <netdb.h>
    20. #include <sys/time.h>
    21. #include <string.h>
    22. #include <unistd.h>
    23. #include <stdio.h>
    24. #include <stdlib.h>
    25. #include <stdarg.h>
    26. int Socket(const char *host, int clientPort)
    27. {
    28. int sock;
    29. unsigned long inaddr;
    30. struct sockaddr_in ad;
    31. struct hostent *hp;
    32. //获取host
    33. memset(&ad, 0, sizeof(ad));
    34. ad.sin_family = AF_INET;
    35. inaddr = inet_addr(host);
    36. if (inaddr != INADDR_NONE)
    37. memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
    38. else
    39. {
    40. hp = gethostbyname(host);
    41. if (hp == NULL)
    42. return -1;
    43. memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
    44. }
    45. ad.sin_port = htons(clientPort);
    46. //socket建立
    47. sock = socket(AF_INET, SOCK_STREAM, 0);
    48. if (sock < 0)
    49. return sock;
    50. //连接
    51. if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0)
    52. return -1;
    53. return sock;
    54. }

    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. //这里只有本文件用到了socket.c文件,所以可以这样包含进来
    20. #include <unistd.h>
    21. #include <sys/param.h>
    22. #include <rpc/types.h>
    23. #include <getopt.h>
    24. #include <strings.h>
    25. #include <time.h>
    26. #include <signal.h>
    27. /* values */
    28. volatile int timerexpired=0;
    29. int speed=0;
    30. int failed=0;
    31. int bytes=0;
    32. /* globals */
    33. int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */
    34. /* Allow: GET, HEAD, OPTIONS, TRACE */
    35. #define METHOD_GET 0
    36. #define METHOD_HEAD 1
    37. #define METHOD_OPTIONS 2
    38. #define METHOD_TRACE 3
    39. #define PROGRAM_VERSION "1.5"
    40. int method=METHOD_GET;
    41. int clients=1;
    42. int force=0;
    43. int force_reload=0;
    44. int proxyport=80;
    45. char *proxyhost=NULL;
    46. int benchtime=30;
    47. /* internal */
    48. int mypipe[2];
    49. char host[MAXHOSTNAMELEN];
    50. #define REQUEST_SIZE 2048
    51. char request[REQUEST_SIZE];
    52. static const struct option long_options[]=
    53. {
    54. {"force",no_argument,&force,1},
    55. {"reload",no_argument,&force_reload,1},
    56. {"time",required_argument,NULL,'t'},
    57. {"help",no_argument,NULL,'?'},
    58. {"http09",no_argument,NULL,'9'},
    59. {"http10",no_argument,NULL,'1'},
    60. {"http11",no_argument,NULL,'2'},
    61. {"get",no_argument,&method,METHOD_GET},
    62. {"head",no_argument,&method,METHOD_HEAD},
    63. {"options",no_argument,&method,METHOD_OPTIONS},
    64. {"trace",no_argument,&method,METHOD_TRACE},
    65. {"version",no_argument,NULL,'V'},
    66. {"proxy",required_argument,NULL,'p'},
    67. {"clients",required_argument,NULL,'c'},
    68. {NULL,0,NULL,0}
    69. };
    70. /* prototypes */
    71. static void benchcore(const char* host,const int port, const char *request);
    72. static int bench(void);
    73. static void build_request(const char *url);
    74. static void alarm_handler(int signal)
    75. {
    76. timerexpired=1;
    77. }
    78. static void usage(void)
    79. {//标准错误输出打印下面的字符串,在"" ""中代表一个连续的字符串
    80. fprintf(stderr,
    81. "webbench [option]... URL "
    82. " -f|--force Don't wait for reply from server. "
    83. " -r|--reload Send reload request - Pragma: no-cache. "
    84. " -t|--time <sec> Run benchmark for <sec> seconds. Default 30. "
    85. " -p|--proxy <server:port> Use proxy server for request. "
    86. " -c|--clients <n> Run <n> HTTP clients at once. Default one. "
    87. " -9|--http09 Use HTTP/0.9 style requests. "
    88. " -1|--http10 Use HTTP/1.0 protocol. "
    89. " -2|--http11 Use HTTP/1.1 protocol. "
    90. " --get Use GET request method. "
    91. " --head Use HEAD request method. "
    92. " --options Use OPTIONS request method. "
    93. " --trace Use TRACE request method. "
    94. " -?|-h|--help This information. "
    95. " -V|--version Display program version. "
    96. );
    97. };
    98. int main(int argc, char *argv[])
    99. {
    100. int opt=0;
    101. int options_index=0;
    102. char *tmp=NULL;
    103. //检查参数,参数不对进行用法展示
    104. if(argc==1)
    105. {
    106. usage();
    107. return 2;
    108. }
    109. //获取传入的命令行参数,根据long_options设置进行返回。optarg和optind为外部变量
    110. while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF )
    111. {//根据解析出的参数进行赋值到变量中进行后续的使用
    112. switch(opt)
    113. {
    114. case 0 : break;
    115. case 'f': force=1;break;
    116. case 'r': force_reload=1;break;
    117. case '9': http10=0;break;
    118. case '1': http10=1;break;
    119. case '2': http10=2;break;
    120. case 'V': printf(PROGRAM_VERSION" ");exit(0);
    121. case 't': benchtime=atoi(optarg);break;
    122. case 'p':
    123. /* proxy server parsing server:port */
    124. tmp=strrchr(optarg,':');
    125. proxyhost=optarg;
    126. if(tmp==NULL)
    127. {
    128. break;
    129. }
    130. if(tmp==optarg)
    131. {
    132. fprintf(stderr,"Error in option --proxy %s: Missing hostname. ",optarg);
    133. return 2;
    134. }
    135. if(tmp==optarg+strlen(optarg)-1)
    136. {
    137. fprintf(stderr,"Error in option --proxy %s Port number is missing. ",optarg);
    138. return 2;
    139. }
    140. *tmp='';
    141. proxyport=atoi(tmp+1);break;
    142. case ':':
    143. case 'h':
    144. case '?': usage();return 2;break;
    145. case 'c': clients=atoi(optarg);break;
    146. }
    147. }
    148. //检查参数个数
    149. if(optind==argc)
    150. {
    151. fprintf(stderr,"webbench: Missing URL! ");
    152. usage();
    153. return 2;
    154. }
    155. //检查客户并发数和测试时间,并对违法的设置给出默认的值
    156. if(clients==0) clients=1;
    157. if(benchtime==0) benchtime=60;
    158. /* Copyright */
    159. fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION" "
    160. "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software. "
    161. );
    162. //建立requst命令
    163. build_request(argv[optind]);
    164. /* print bench info */
    165. printf(" Benchmarking: ");
    166. switch(method)
    167. {
    168. case METHOD_GET:
    169. default:
    170. printf("GET");break;
    171. case METHOD_OPTIONS:
    172. printf("OPTIONS");break;
    173. case METHOD_HEAD:
    174. printf("HEAD");break;
    175. case METHOD_TRACE:
    176. printf("TRACE");break;
    177. }
    178. printf(" %s",argv[optind]);
    179. switch(http10)
    180. {
    181. case 0: printf(" (using HTTP/0.9)");break;
    182. case 2: printf(" (using HTTP/1.1)");break;
    183. }
    184. printf(" ");
    185. if(clients==1) printf("1 client");
    186. else
    187. printf("%d clients",clients);
    188. printf(", running %d sec", benchtime);
    189. if(force) printf(", early socket close");
    190. if(proxyhost!=NULL) printf(", via proxy server %s:%d",proxyhost,proxyport);
    191. if(force_reload) printf(", forcing reload");
    192. printf(". ");
    193. //以上区间为打印的提示信息,下面的主处理
    194. return bench();
    195. }
    196. void build_request(const char *url)
    197. {
    198. char tmp[10];
    199. int i;
    200. //清零
    201. bzero(host,MAXHOSTNAMELEN);
    202. bzero(request,REQUEST_SIZE);
    203. //设置版本http
    204. if(force_reload && proxyhost!=NULL && http10<1) http10=1;
    205. if(method==METHOD_HEAD && http10<1) http10=1;
    206. if(method==METHOD_OPTIONS && http10<2) http10=2;
    207. if(method==METHOD_TRACE && http10<2) http10=2;
    208. //测试方式
    209. switch(method)
    210. {
    211. default:
    212. case METHOD_GET: strcpy(request,"GET");break;
    213. case METHOD_HEAD: strcpy(request,"HEAD");break;
    214. case METHOD_OPTIONS: strcpy(request,"OPTIONS");break;
    215. case METHOD_TRACE: strcpy(request,"TRACE");break;
    216. }
    217. //拼接requset命令
    218. strcat(request," ");
    219. if(NULL==strstr(url,"://"))
    220. {
    221. fprintf(stderr, " %s: is not a valid URL. ",url);
    222. exit(2);
    223. }
    224. if(strlen(url)>1500)
    225. {
    226. fprintf(stderr,"URL is too long. ");
    227. exit(2);
    228. }
    229. if(proxyhost==NULL)
    230. if (0!=strncasecmp("http://",url,7))
    231. {
    232. fprintf(stderr," Only HTTP protocol is directly supported, set --proxy for others. ");
    233. exit(2);
    234. }
    235. /* protocol/host delimiter */
    236. i=strstr(url,"://")-url+3;
    237. /* printf("%d ",i); */
    238. if(strchr(url+i,'/')==NULL)
    239. {
    240. fprintf(stderr," Invalid URL syntax - hostname don't ends with '/'. ");
    241. exit(2);
    242. }
    243. if(proxyhost==NULL)
    244. {
    245. /* get port from hostname */
    246. if(index(url+i,':')!=NULL && index(url+i,':')<index(url+i,'/'))
    247. {
    248. strncpy(host,url+i,strchr(url+i,':')-url-i);
    249. bzero(tmp,10);
    250. strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1);
    251. /* printf("tmp=%s ",tmp); */
    252. proxyport=atoi(tmp);
    253. if(proxyport==0) proxyport=80;
    254. }
    255. else
    256. {
    257. strncpy(host,url+i,strcspn(url+i,"/"));
    258. }
    259. // printf("Host=%s ",host);
    260. strcat(request+strlen(request),url+i+strcspn(url+i,"/"));
    261. }
    262. else
    263. {
    264. // printf("ProxyHost=%s ProxyPort=%d ",proxyhost,proxyport);
    265. strcat(request,url);
    266. }
    267. if(http10==1)
    268. strcat(request," HTTP/1.0");
    269. else if (http10==2)
    270. strcat(request," HTTP/1.1");
    271. strcat(request," ");
    272. if(http10>0)
    273. strcat(request,"User-Agent: WebBench "PROGRAM_VERSION" ");
    274. if(proxyhost==NULL && http10>0)
    275. {
    276. strcat(request,"Host: ");
    277. strcat(request,host);
    278. strcat(request," ");
    279. }
    280. if(force_reload && proxyhost!=NULL)
    281. {
    282. strcat(request,"Pragma: no-cache ");
    283. }
    284. if(http10>1)
    285. strcat(request,"Connection: close ");
    286. /* add empty line at end */
    287. if(http10>0) strcat(request," ");
    288. // printf("Req=%s ",request);
    289. }
    290. /* vraci system rc error kod */
    291. static int bench(void)
    292. {
    293. int i,j,k;
    294. pid_t pid=0;
    295. FILE *f;
    296. /* check avaibility of target server */
    297. i=Socket(proxyhost==NULL?host:proxyhost,proxyport);
    298. if(i<0)
    299. {
    300. fprintf(stderr," Connect to server failed. Aborting benchmark. ");
    301. return 1;
    302. }
    303. close(i);
    304. /* create pipe */
    305. if(pipe(mypipe))
    306. {
    307. perror("pipe failed.");
    308. return 3;
    309. }
    310. /* not needed, since we have alarm() in childrens */
    311. /* wait 4 next system clock tick */
    312. /*
    313. cas=time(NULL);
    314. while(time(NULL)==cas)
    315. sched_yield();
    316. */
    317. /* fork childs */
    318. for(i=0;i<clients;i++)
    319. {
    320. pid=fork();
    321. if(pid <= (pid_t) 0)
    322. {
    323. /* child process or error*/
    324. sleep(1); /* make childs faster */
    325. break;
    326. }
    327. }
    328. if( pid< (pid_t) 0)
    329. {
    330. fprintf(stderr,"problems forking worker no. %d ",i);
    331. perror("fork failed.");
    332. return 3;
    333. }
    334. if(pid== (pid_t) 0)
    335. {
    336. /* I am a child */
    337. //子进程进行
    338. if(proxyhost==NULL)
    339. benchcore(host,proxyport,request);
    340. else
    341. benchcore(proxyhost,proxyport,request);
    342. /* write results to pipe */
    343. //将得到的信息进行打印到管道里面
    344. f=fdopen(mypipe[1],"w");
    345. if(f==NULL)
    346. {
    347. perror("open pipe for writing failed.");
    348. return 3;
    349. }
    350. /* fprintf(stderr,"Child - %d %d ",speed,failed); */
    351. fprintf(f,"%d %d %d ",speed,failed,bytes);
    352. fclose(f);
    353. return 0;
    354. } else
    355. {
    356. //父进程进行统计信息
    357. f=fdopen(mypipe[0],"r");
    358. if(f==NULL)
    359. {
    360. perror("open pipe for reading failed.");
    361. return 3;
    362. }
    363. setvbuf(f,NULL,_IONBF,0);
    364. speed=0;
    365. failed=0;
    366. bytes=0;
    367. while(1)
    368. {//读取管道中的值
    369. pid=fscanf(f,"%d %d %d",&i,&j,&k);
    370. if(pid<2)
    371. {
    372. fprintf(stderr,"Some of our childrens died. ");
    373. break;
    374. }
    375. speed+=i;
    376. failed+=j;
    377. bytes+=k;
    378. /* fprintf(stderr,"*Knock* %d %d read=%d ",speed,failed,pid); */
    379. if(--clients==0) break;
    380. }
    381. fclose(f);
    382. //输出统计出的信息
    383. printf(" Speed=%d pages/min, %d bytes/sec. Requests: %d susceed, %d failed. ",
    384. (int)((speed+failed)/(benchtime/60.0f)),
    385. (int)(bytes/(float)benchtime),
    386. speed,
    387. failed);
    388. }
    389. return i;
    390. }
    391. void benchcore(const char *host,const int port,const char *req)
    392. {
    393. int rlen;
    394. char buf[1500];
    395. int s,i;
    396. struct sigaction sa;
    397. //设置定时器信号
    398. /* setup alarm signal handler */
    399. sa.sa_handler=alarm_handler;
    400. sa.sa_flags=0;
    401. if(sigaction(SIGALRM,&sa,NULL))
    402. exit(3);
    403. alarm(benchtime);
    404. //在时间段内进行循环的访问request命令和接收回复并进行统计
    405. rlen=strlen(req);
    406. nexttry:while(1)
    407. {
    408. if(timerexpired)
    409. {
    410. if(failed>0)
    411. {
    412. /* fprintf(stderr,"Correcting failed by signal "); */
    413. failed--;
    414. }
    415. return;
    416. }
    417. s=Socket(host,port);
    418. if(s<0) { failed++;continue;}
    419. if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;}
    420. if(http10==0)
    421. if(shutdown(s,1)) { failed++;close(s);continue;}
    422. if(force==0)
    423. {
    424. /* read all available data from socket */
    425. while(1)
    426. {
    427. if(timerexpired) break;
    428. i=read(s,buf,1500);
    429. /* fprintf(stderr,"%d ",i); */
    430. if(i<0)
    431. {
    432. failed++;
    433. close(s);
    434. goto nexttry;
    435. }
    436. else
    437. if(i==0) break;
    438. else
    439. bytes+=i;
    440. }
    441. }
    442. if(close(s)) {failed++;continue;}
    443. speed++;
    444. }
    445. }

    一个比较见到处理流程示意图,其中忽略了错误处理,只体现了大致的处理过程。





  • 相关阅读:
    CodeForces Round #288 Div.2
    POJ 3660 Cow Contest【传递闭包】
    ZOJ 3321 Circle【并查集】
    CF 286(div 2) B Mr. Kitayuta's Colorful Graph【传递闭包】
    CF 287(div 2) B Amr and Pins
    HDU 2122 Ice_cream’s world III【最小生成树】
    HDU 1233 还是畅通工程【最小生成树】
    奶牛接力 矩阵乘法
    家谱 并差集
    昂贵的聘礼 最短路 dijkstra
  • 原文地址:https://www.cnblogs.com/cfzhang/p/705e45f34ccda8fc10e6e2003797c374.html
Copyright © 2011-2022 走看看