├── COPYRIGHT ├── ChangeLog ├── Makefile ├── README.md ├── debian ├── changelog ├── control ├── copyright ├── dirs └── rules ├── socket.c ├── tags ├── webbench.1 ├── webbench.c └── webbench.o /COPYRIGHT: -------------------------------------------------------------------------------- 1 | debian/copyright -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | debian/changelog -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS?= -Wall -ggdb -W -O 2 | CC?= gcc 3 | LIBS?= 4 | LDFLAGS?= 5 | PREFIX?= /usr/local 6 | VERSION=1.5 7 | TMPDIR=/tmp/webbench-$(VERSION) 8 | 9 | all: webbench tags 10 | 11 | tags: *.c 12 | -ctags *.c 13 | 14 | install: webbench 15 | install -s webbench $(DESTDIR)$(PREFIX)/bin 16 | install -m 644 webbench.1 $(DESTDIR)$(PREFIX)/man/man1 17 | install -d $(DESTDIR)$(PREFIX)/share/doc/webbench 18 | install -m 644 debian/copyright $(DESTDIR)$(PREFIX)/share/doc/webbench 19 | install -m 644 debian/changelog $(DESTDIR)$(PREFIX)/share/doc/webbench 20 | 21 | webbench: webbench.o Makefile 22 | $(CC) $(CFLAGS) $(LDFLAGS) -o webbench webbench.o $(LIBS) 23 | 24 | clean: 25 | -rm -f *.o webbench *~ core *.core tags 26 | 27 | tar: clean 28 | -debian/rules clean 29 | rm -rf $(TMPDIR) 30 | install -d $(TMPDIR) 31 | cp -p Makefile webbench.c socket.c webbench.1 $(TMPDIR) 32 | install -d $(TMPDIR)/debian 33 | -cp -p debian/* $(TMPDIR)/debian 34 | ln -sf debian/copyright $(TMPDIR)/COPYRIGHT 35 | ln -sf debian/changelog $(TMPDIR)/ChangeLog 36 | -cd $(TMPDIR) && cd .. && tar cozf webbench-$(VERSION).tar.gz webbench-$(VERSION) 37 | 38 | webbench.o: webbench.c socket.c Makefile 39 | 40 | .PHONY: clean install all tar 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 项目说明 2 | Webbench是C语言开发的网站压测工具,性能良好, 推荐作为经典项目进行源码阅读。 3 | 该项目通过对Webbench项目的源码分析,理解其多进程模拟请求的模型及编码规范与技巧。 4 | 主要通过以下方式阅读源码: 5 | * 通读代码,增加部分注释信息 6 | * 绘制程序流程图、函数调用关系图 7 | * 总结多进程模型等程序设计思想的优劣 8 | 9 | 完整的分析记录参见此文:[WebBench源码阅读](http://fivezh.github.io/2016/03/27/OpenCode-webbench-source-code-reading/) 10 | 11 | ``` 12 | five@master:~/github/openCode/WebBench$ ./webbench http://www.baidu.com/ 13 | Webbench - Simple Web Benchmark 1.5 14 | Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software. 15 | 16 | Benchmarking: GET http://www.baidu.com/ 17 | 1 client, running 30 sec. 18 | 19 | Speed=732 pages/min, 1211136 bytes/sec. 20 | Requests: 366 susceed, 0 failed. 21 | ``` 22 | 23 | # WebBench 24 | Webbench是一个在linux下使用的非常简单的网站压测工具。它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能,最多可以模拟3万个并发连接去测试网站的负载能力。Webbench使用C语言编写, 代码实在太简洁,源码加起来不到600行。 25 | 26 | 使用: 27 | sudo make clean 28 | 29 | sudo make && make install 30 | 31 | 命令行选项: 32 | 33 | -f|--force 不需要等待服务器响应 34 | -r|--reload 发送重新加载请求 35 | -t|--time 运行多长时间,单位:秒" 36 | -p|--proxy 使用代理服务器来发送请求 37 | -c|--clients 创建多少个客户端,默认1个" 38 | -9|--http09 使用 HTTP/0.9 39 | -1|--http10 使用 HTTP/1.0 协议 40 | -2|--http11 使用 HTTP/1.1 协议 41 | --get 使用 GET请求方法 42 | --head 使用 HEAD请求方 43 | --options 使用 OPTIONS请求方法 44 | --trace 使用 TRACE请求方法 45 | -?|-h|--help 打印帮助信息 46 | -V|--version 显示版本号 47 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | webbench (1.5) unstable; urgency=low 2 | 3 | * allow building with both Gnu and BSD make 4 | 5 | -- Radim Kolar Fri, Jun 25 12:00:20 CEST 2004 6 | 7 | webbench (1.4) unstable; urgency=low 8 | 9 | * check if url is not too long 10 | * report correct program version number 11 | * use yield() when waiting for test start 12 | * corrected error codes 13 | * check availability of test server first 14 | * do not abort test if first request failed 15 | * report when some childrens are dead. 16 | * use alarm, not time() for lower syscal use by bench 17 | * use mode 644 for installed doc 18 | * makefile cleaned for better freebsd ports integration 19 | 20 | -- Radim Kolar Thu, 15 Jan 2004 11:15:52 +0100 21 | 22 | webbench (1.3) unstable; urgency=low 23 | 24 | * Build fixes for freeBSD 25 | * Default benchmark time 60 -> 30 26 | * generate tar with subdirectory 27 | * added to freeBSD ports collection 28 | 29 | -- Radim Kolar Mon, 12 Jan 2004 17:00:24 +0100 30 | 31 | webbench (1.2) unstable; urgency=low 32 | 33 | * Only debian-related bugfixes 34 | * Updated Debian/rules 35 | * Adapted to fit new directory system 36 | * moved from debstd to dh_* 37 | 38 | -- Radim Kolar Fri, 18 Jan 2002 12:33:04 +0100 39 | 40 | webbench (1.1) unstable; urgency=medium 41 | 42 | * Program debianized 43 | * added support for multiple methods (GET, HEAD, OPTIONS, TRACE) 44 | * added support for multiple HTTP versions (0.9 -- 1.1) 45 | * added long options 46 | * added multiple clients 47 | * wait for start of second before test 48 | * test time can be specified 49 | * better error checking when reading reply from server 50 | * FIX: tests was one second longer than expected 51 | 52 | -- Radim Kolar Thu, 16 Sep 1999 18:48:00 +0200 53 | 54 | Local variables: 55 | mode: debian-changelog 56 | End: 57 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: webbench 2 | Section: web 3 | Priority: extra 4 | Maintainer: Radim Kolar 5 | Build-Depends: debhelper (>> 3.0.0) 6 | Standards-Version: 3.5.2 7 | 8 | Package: webbench 9 | Architecture: any 10 | Depends: ${shlibs:Depends} 11 | Description: Simple forking Web benchmark 12 | webbench is very simple program for benchmarking WWW or Proxy servers. 13 | Uses fork() for simulating multiple clients load. Can use HTTP 0.9 - 1.1 14 | requests, but Keep-Alive connections are not supported. 15 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Webbench was written by Radim Kolar 1997-2004 (hsn@netmag.cz). 2 | 3 | UNIX sockets code (socket.c) taken from popclient 1.5 4/1/94 4 | public domain code, created by Virginia Tech Computing Center. 5 | 6 | Copyright: GPL (see /usr/share/common-licenses/GPL) 7 | -------------------------------------------------------------------------------- /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/bin -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # Sample debian/rules that uses debhelper. 3 | # GNU copyright 1997 to 1999 by Joey Hess. 4 | 5 | # Uncomment this to turn on verbose mode. 6 | #export DH_VERBOSE=1 7 | 8 | # This is the debhelper compatability version to use. 9 | export DH_COMPAT=3 10 | 11 | configure: configure-stamp 12 | configure-stamp: 13 | dh_testdir 14 | touch configure-stamp 15 | 16 | build: configure-stamp build-stamp 17 | build-stamp: 18 | dh_testdir 19 | $(MAKE) 20 | touch build-stamp 21 | 22 | clean: 23 | dh_testdir 24 | rm -f build-stamp configure-stamp 25 | 26 | # Add here commands to clean up after the build process. 27 | -$(MAKE) clean 28 | 29 | dh_clean 30 | 31 | install: build 32 | dh_testdir 33 | dh_testroot 34 | dh_clean -k 35 | dh_installdirs 36 | 37 | # Add here commands to install the package into debian/webbench. 38 | $(MAKE) install DESTDIR=$(CURDIR)/debian/webbench 39 | 40 | 41 | # Build architecture-independent files here. 42 | binary-indep: build install 43 | # We have nothing to do by default. 44 | 45 | # Build architecture-dependent files here. 46 | binary-arch: build install 47 | dh_testdir 48 | dh_testroot 49 | dh_installdocs 50 | dh_installman webbench.1 51 | dh_installchangelogs 52 | dh_link 53 | dh_strip 54 | dh_compress 55 | dh_fixperms 56 | # dh_makeshlibs 57 | dh_installdeb 58 | dh_shlibdeps 59 | dh_gencontrol 60 | dh_md5sums 61 | dh_builddeb 62 | 63 | binary: binary-indep binary-arch 64 | .PHONY: build clean binary-indep binary-arch binary install configure 65 | -------------------------------------------------------------------------------- /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 | /*********************************************************************** 7 | module: socket.c 8 | program: popclient 9 | SCCS ID: @(#)socket.c 1.5 4/1/94 10 | programmer: Virginia Tech Computing Center 11 | compiler: DEC RISC C compiler (Ultrix 4.1) 12 | environment: DEC Ultrix 4.3 13 | description: UNIX sockets code. 14 | ***********************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | int Socket(const char *host, int clientPort) 30 | { 31 | int sock; 32 | unsigned long inaddr; 33 | struct sockaddr_in ad; 34 | struct hostent *hp; 35 | 36 | memset(&ad, 0, sizeof(ad)); 37 | ad.sin_family = AF_INET; 38 | 39 | inaddr = inet_addr(host); 40 | if (inaddr != INADDR_NONE) 41 | memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr)); 42 | else 43 | { 44 | hp = gethostbyname(host); 45 | if (hp == NULL) 46 | return -1; 47 | memcpy(&ad.sin_addr, hp->h_addr, hp->h_length); 48 | } 49 | ad.sin_port = htons(clientPort); 50 | 51 | sock = socket(AF_INET, SOCK_STREAM, 0); 52 | if (sock < 0) 53 | return sock; 54 | if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0) 55 | return -1; 56 | return sock; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /tags: -------------------------------------------------------------------------------- 1 | !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ 2 | !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ 3 | !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ 4 | !_TAG_PROGRAM_NAME Exuberant Ctags // 5 | !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ 6 | !_TAG_PROGRAM_VERSION 5.9~svn20110310 // 7 | METHOD_GET webbench.c 35;" d file: 8 | METHOD_HEAD webbench.c 36;" d file: 9 | METHOD_OPTIONS webbench.c 37;" d file: 10 | METHOD_TRACE webbench.c 38;" d file: 11 | PROGRAM_VERSION webbench.c 39;" d file: 12 | REQUEST_SIZE webbench.c 50;" d file: 13 | Socket socket.c /^int Socket(const char *host, int clientPort)$/;" f 14 | alarm_handler webbench.c /^static void alarm_handler(int signal)$/;" f file: 15 | bench webbench.c /^static int bench(void)$/;" f file: 16 | benchcore webbench.c /^void benchcore(const char *host,const int port,const char *req)$/;" f 17 | benchtime webbench.c /^int benchtime=30;$/;" v 18 | build_request webbench.c /^void build_request(const char *url)$/;" f 19 | bytes webbench.c /^int bytes=0;$/;" v 20 | clients webbench.c /^int clients=1;$/;" v 21 | failed webbench.c /^int failed=0;$/;" v 22 | force webbench.c /^int force=0;$/;" v 23 | force_reload webbench.c /^int force_reload=0;$/;" v 24 | host webbench.c /^char host[MAXHOSTNAMELEN];$/;" v 25 | http10 webbench.c /^int http10=1; \/* 0 - http\/0.9, 1 - http\/1.0, 2 - http\/1.1 *\/$/;" v 26 | long_options webbench.c /^static const struct option long_options[]=$/;" v typeref:struct:option file: 27 | main webbench.c /^int main(int argc, char *argv[])$/;" f 28 | method webbench.c /^int method=METHOD_GET;$/;" v 29 | mypipe webbench.c /^int mypipe[2];$/;" v 30 | proxyhost webbench.c /^char *proxyhost=NULL;$/;" v 31 | proxyport webbench.c /^int proxyport=80;$/;" v 32 | request webbench.c /^char request[REQUEST_SIZE];$/;" v 33 | speed webbench.c /^int speed=0;$/;" v 34 | timerexpired webbench.c /^volatile int timerexpired=0;$/;" v 35 | usage webbench.c /^static void usage(void)$/;" f file: 36 | -------------------------------------------------------------------------------- /webbench.1: -------------------------------------------------------------------------------- 1 | .TH WEBBENCH 1 "14 Jan 2004" 2 | .\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection 3 | .\" other parms are allowed: see man(7), man(1) 4 | .SH NAME 5 | webbench \- simple forking web benchmark 6 | .SH SYNOPSIS 7 | .B webbench 8 | .I "[options] URL" 9 | .br 10 | .SH "AUTHOR" 11 | This program and manual page was written by Radim Kolar, 12 | for the 13 | .B Supreme Personality of Godhead 14 | (but may be used by others). 15 | .SH "DESCRIPTION" 16 | .B webbench 17 | is simple program for benchmarking HTTP servers or any 18 | other servers, which can be accessed via HTTP proxy. Unlike others 19 | benchmarks, 20 | .B webbench 21 | uses multiple processes for simulating traffic 22 | generated by multiple users. This allows better operating 23 | on SMP systems and on systems with slow or buggy implementation 24 | of select(). 25 | .SH OPTIONS 26 | The programs follow the usual GNU command line syntax, with long 27 | options starting with two dashes (`-'). 28 | A summary of options are included below. 29 | .TP 30 | .B \-?, \-h, \-\-help 31 | Show summary of options. 32 | .TP 33 | .B \-v, \-\-version 34 | Show version of program. 35 | .TP 36 | .B \-f, \-\-force 37 | Do not wait for any response from server. Close connection after 38 | request is send. This option produce quite a good denial of service 39 | attack. 40 | .TP 41 | .B \-9, \-\-http09 42 | Use HTTP/0.9 protocol, if possible. 43 | .TP 44 | .B \-1, \-\-http10 45 | Use HTTP/1.0 protocol, if possible. 46 | .TP 47 | .B \-2, \-\-http11 48 | Use HTTP/1.1 protocol (without 49 | .I Keep-Alive 50 | ), if possible. 51 | .TP 52 | .B \-r, \-\-reload 53 | Forces proxy to reload document. If proxy is not 54 | set, option has no effect. 55 | .TP 56 | .B \-t, \-\-time 57 | Run benchmark for 58 | .I 59 | seconds. Default value is 30. 60 | .TP 61 | .B \-p, \-\-proxy 62 | Send request via proxy server. Needed for supporting others protocols 63 | than HTTP. 64 | .TP 65 | .B \-\-get 66 | Use GET request method. 67 | .TP 68 | .B \-\-head 69 | Use HEAD request method. 70 | .TP 71 | .B \-\-options 72 | Use OPTIONS request method. 73 | .TP 74 | .B \-\-trace 75 | Use TRACE request method. 76 | .TP 77 | .B \-c, \-\-clients 78 | Use 79 | .I 80 | multiple clients for benchmark. Default value 81 | is 1. 82 | .SH "EXIT STATUS" 83 | .TP 84 | 0 - sucess 85 | .TP 86 | 1 - benchmark failed, can not connect to server 87 | .TP 88 | 2 - bad command line argument(s) 89 | .TP 90 | 3 - internal error, i.e. fork failed 91 | .SH "TODO" 92 | Include support for using 93 | .I Keep-Alive 94 | HTTP/1.1 connections. 95 | .SH "COPYING" 96 | Webbench is distributed under GPL. Copyright 1997-2004 97 | Radim Kolar (hsn@netmag.cz). 98 | UNIX sockets code taken from popclient 1.5 4/1/94 99 | public domain code, created by Virginia Tech Computing Center. 100 | .BR 101 | This man page is public domain. 102 | -------------------------------------------------------------------------------- /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 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 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 | 53 | static const struct option long_options[]= 54 | { 55 | {"force",no_argument,&force,1}, 56 | {"reload",no_argument,&force_reload,1}, 57 | {"time",required_argument,NULL,'t'}, 58 | {"help",no_argument,NULL,'?'}, 59 | {"http09",no_argument,NULL,'9'}, 60 | {"http10",no_argument,NULL,'1'}, 61 | {"http11",no_argument,NULL,'2'}, 62 | {"get",no_argument,&method,METHOD_GET}, 63 | {"head",no_argument,&method,METHOD_HEAD}, 64 | {"options",no_argument,&method,METHOD_OPTIONS}, 65 | {"trace",no_argument,&method,METHOD_TRACE}, 66 | {"version",no_argument,NULL,'V'}, 67 | {"proxy",required_argument,NULL,'p'}, 68 | {"clients",required_argument,NULL,'c'}, 69 | {NULL,0,NULL,0} 70 | }; 71 | 72 | /* prototypes */ 73 | static void benchcore(const char* host,const int port, const char *request); 74 | static int bench(void); 75 | static void build_request(const char *url); 76 | 77 | static void alarm_handler(int signal) 78 | { 79 | timerexpired=1; 80 | } 81 | 82 | static void usage(void) 83 | { 84 | fprintf(stderr, 85 | "webbench [option]... URL\n" 86 | " -f|--force Don't wait for reply from server.\n" 87 | " -r|--reload Send reload request - Pragma: no-cache.\n" 88 | " -t|--time Run benchmark for seconds. Default 30.\n" 89 | " -p|--proxy Use proxy server for request.\n" 90 | " -c|--clients Run HTTP clients at once. Default one.\n" 91 | " -9|--http09 Use HTTP/0.9 style requests.\n" 92 | " -1|--http10 Use HTTP/1.0 protocol.\n" 93 | " -2|--http11 Use HTTP/1.1 protocol.\n" 94 | " --get Use GET request method.\n" 95 | " --head Use HEAD request method.\n" 96 | " --options Use OPTIONS request method.\n" 97 | " --trace Use TRACE request method.\n" 98 | " -?|-h|--help This information.\n" 99 | " -V|--version Display program version.\n" 100 | ); 101 | }; 102 | int main(int argc, char *argv[]) 103 | { 104 | int opt=0; 105 | int options_index=0; 106 | char *tmp=NULL; 107 | 108 | if(argc==1) 109 | { 110 | usage(); 111 | return 2; 112 | } 113 | 114 | while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF ) 115 | //Five_comment: manual of getopt() http://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Options.html#Getopt-Long-Options 116 | { 117 | switch(opt) 118 | { 119 | case 0 : break; 120 | case 'f': force=1;break; 121 | case 'r': force_reload=1;break; 122 | case '9': http10=0;break; 123 | case '1': http10=1;break; 124 | case '2': http10=2;break; 125 | case 'V': printf(PROGRAM_VERSION"\n");exit(0); 126 | case 't': benchtime=atoi(optarg);break; 127 | case 'p': 128 | /* proxy server parsing server:port */ 129 | tmp=strrchr(optarg,':'); 130 | proxyhost=optarg;//xxxx:8080 131 | if(tmp==NULL) 132 | { 133 | break; 134 | } 135 | if(tmp==optarg) 136 | { 137 | fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg); 138 | return 2; 139 | } 140 | if(tmp==optarg+strlen(optarg)-1) 141 | { 142 | fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg); 143 | return 2; 144 | } 145 | *tmp='\0';// here will sepreate proxyhost and port 146 | proxyport=atoi(tmp+1);break; 147 | case ':': 148 | case 'h': 149 | case '?': usage();return 2;break; 150 | case 'c': clients=atoi(optarg);break; 151 | } 152 | } 153 | //Five_comment: getopt_long() will reorder the options and move the non-option argvs to the last of argv. 154 | 155 | if(optind==argc) { //this means all paras have been parsed. So lack of URL. 156 | fprintf(stderr,"webbench: Missing URL!\n"); 157 | usage(); 158 | return 2; 159 | } 160 | //Five_comment: in case user set these option to invalid value. reset them. 161 | if(clients==0) clients=1; 162 | if(benchtime==0) benchtime=60; 163 | /* Copyright */ 164 | fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n" 165 | "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n" 166 | ); 167 | //Five_comment: optind will point to the last value in argv. 168 | build_request(argv[optind]);// in here optind will point to the last para in argv, That is argv[optind]==URL 169 | /* print bench info */ 170 | printf("\nBenchmarking: "); 171 | switch(method) 172 | { 173 | case METHOD_GET: 174 | default: 175 | printf("GET");break; 176 | case METHOD_OPTIONS: 177 | printf("OPTIONS");break; 178 | case METHOD_HEAD: 179 | printf("HEAD");break; 180 | case METHOD_TRACE: 181 | printf("TRACE");break; 182 | } 183 | printf(" %s",argv[optind]);// print request url 184 | switch(http10)// default using HTTP/1.0 185 | { 186 | case 0: printf(" (using HTTP/0.9)");break; 187 | case 2: printf(" (using HTTP/1.1)");break; 188 | } 189 | printf("\n"); 190 | if(clients==1) printf("1 client"); //default client count 191 | else 192 | printf("%d clients",clients); 193 | 194 | printf(", running %d sec", benchtime); 195 | if(force) printf(", early socket close"); 196 | if(proxyhost!=NULL) printf(", via proxy server %s:%d",proxyhost,proxyport); 197 | if(force_reload) printf(", forcing reload"); 198 | printf(".\n"); 199 | return bench(); 200 | } 201 | 202 | void build_request(const char *url) 203 | { 204 | char tmp[10]; 205 | int i; 206 | 207 | //Five_comment: same as memset bytes to sezo('\0') 208 | bzero(host,MAXHOSTNAMELEN); 209 | bzero(request,REQUEST_SIZE); 210 | 211 | //setting http version 212 | if(force_reload && proxyhost!=NULL && http10<1) http10=1; 213 | if(method==METHOD_HEAD && http10<1) http10=1; 214 | if(method==METHOD_OPTIONS && http10<2) http10=2; 215 | if(method==METHOD_TRACE && http10<2) http10=2; 216 | 217 | //value of method is set while handling the long_options 218 | switch(method) 219 | { 220 | default: 221 | case METHOD_GET: strcpy(request,"GET");break; 222 | case METHOD_HEAD: strcpy(request,"HEAD");break; 223 | case METHOD_OPTIONS: strcpy(request,"OPTIONS");break; 224 | case METHOD_TRACE: strcpy(request,"TRACE");break; 225 | } 226 | 227 | strcat(request," "); 228 | 229 | //Five_comment: strstr return the first place of "://" in url 230 | if(NULL==strstr(url,"://")) 231 | { 232 | fprintf(stderr, "\n%s: is not a valid URL.\n",url); 233 | exit(2); 234 | } 235 | if(strlen(url)>1500) 236 | { 237 | fprintf(stderr,"URL is too long.\n"); 238 | exit(2); 239 | } 240 | if(proxyhost==NULL) 241 | if (0!=strncasecmp("http://",url,7)) //Five_comment: only http is supported. 242 | { fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n"); 243 | exit(2); 244 | } 245 | /* protocol/host delimiter */ 246 | //Fivezh: url="http://www.baidu.com/" 247 | //Fivezh: i=4+3=7 248 | i=strstr(url,"://")-url+3; 249 | /* printf("%d\n",i); */ 250 | //Fivezh: url+i=="www.baidu.com/" 251 | if(strchr(url+i,'/')==NULL) { 252 | fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n"); 253 | exit(2); 254 | } 255 | if(proxyhost==NULL) 256 | { 257 | /* get port from host and port */ 258 | if(index(url+i,':')!=NULL && 259 | index(url+i,':')0) 286 | strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n"); 287 | if(proxyhost==NULL && http10>0) 288 | { 289 | strcat(request,"Host: "); 290 | strcat(request,host); 291 | strcat(request,"\r\n"); 292 | } 293 | if(force_reload && proxyhost!=NULL) 294 | { 295 | strcat(request,"Pragma: no-cache\r\n"); 296 | } 297 | if(http10>1) 298 | strcat(request,"Connection: close\r\n"); 299 | /* add empty line at end */ 300 | if(http10>0) strcat(request,"\r\n"); 301 | // printf("Req=%s\n",request); 302 | } 303 | 304 | /* vraci system rc error kod */ 305 | static int bench(void) 306 | { 307 | int i,j,k; 308 | pid_t pid=0; 309 | FILE *f; 310 | 311 | /* check avaibility of target server */ 312 | i=Socket(proxyhost==NULL?host:proxyhost,proxyport); 313 | if(i<0) { 314 | fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n"); 315 | return 1; 316 | } 317 | close(i); 318 | /* create pipe *///Five_comment: pipe to communicate with processes 319 | if(pipe(mypipe)) 320 | { 321 | perror("pipe failed."); 322 | return 3; 323 | } 324 | 325 | /* not needed, since we have alarm() in childrens */ 326 | /* wait 4 next system clock tick */ 327 | /* 328 | cas=time(NULL); 329 | while(time(NULL)==cas) 330 | sched_yield(); 331 | */ 332 | 333 | /* fork childs */ 334 | for(i=0;i0) 429 | { 430 | /* fprintf(stderr,"Correcting failed by signal\n"); */ 431 | failed--; 432 | } 433 | return; 434 | } 435 | s=Socket(host,port); 436 | if(s<0) { failed++;continue;} 437 | // write the request to socket will send the request 438 | if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;} 439 | if(http10==0) // TODO: why http0.9 will not get the response data? 440 | if(shutdown(s,1)) { failed++;close(s);continue;} 441 | if(force==0) 442 | { 443 | /* read all available data from socket */ 444 | while(1) 445 | { 446 | if(timerexpired) break; 447 | i=read(s,buf,1500); 448 | /* fprintf(stderr,"%d\n",i); */ 449 | if(i<0) 450 | { 451 | failed++; 452 | close(s); 453 | goto nexttry; 454 | } 455 | else 456 | if(i==0) break; 457 | else 458 | bytes+=i; 459 | } 460 | } 461 | if(close(s)) {failed++;continue;} 462 | speed++; 463 | } 464 | } 465 | -------------------------------------------------------------------------------- /webbench.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fivezh/WebBench/a63fdb4ca516979f3f1961aaeb99633f5e0bb6fa/webbench.o --------------------------------------------------------------------------------