webbench-1.5_hacking
- /****************************************************************************
- *
- * webbench-1.5_hacking
- *
- * 1.这是webbench-1.5版本中webbench.c(主程序)的源码,源码不到700行(除去注释).
- * 2.通过分析、阅读该源码,可以一窥浏览器访问服务器的原理以及web服务器
- * 压力测试的原理.
- * 3.知识量:
- * 1.C语言;
- * 2.Unix或类Unix系统编程;
- * 3.微量的http协议(请求行、消息头、实体内容);
- * 4.如何阅读别人的代码( 从main函数开始 :) );
- * 4.webbench-1.5 文件结构如下:
- * .
- * |-- COPYRIGHT -> debian/copyright
- * |-- ChangeLog -> debian/changelog
- * |-- Makefile -------->makefile 文件
- * |-- debian
- * | |-- changelog
- * | |-- control
- * | |-- copyright
- * | |-- dirs
- * | `-- rules
- * |-- socket.c -------->里面定义了Socket()函数供webbench.c调用
- * |-- webbench.1 -------->说明文档,使用shell命令查看: less webbench.1
- * `-- webbench.c -------->你接下来要阅读的文件
- *
- * 5.如何阅读该文档:
- * 1.linux下使用vi/vim配和ctags,windows下使用Source Insight,当然你也
- * 可以用其他文本编辑器看.
- * 2.先找到main函数,然后就可以开始阅读了,遇到对应的函数,就去看对应的
- * 函数.
- * 3.对于有些函数,本人没有添加注释,或者说本人觉得没必要.
- * 4.祝您好运. :)
- *
- * 6.webbench-1.5版本下载url: http://home.tiscali.cz/~cz210552/webbench.html
- *
- * 如果您对本文有任何意见、提议,可以发邮件至zengjf42@163.com,会尽快回复.
- * 本文的最终解释权归本人(曾剑锋)所有,仅供学习、讨论.
- *
- * 2015-3-24 阴 深圳 尚观 Var
- *
- ***************************************************************************/
- /*
- * (C) Radim Kolar 1997-2004
- * This is free software, see GNU Public License version 2 for
- * details.
- *
- * Simple forking WWW Server benchmark:
- *
- * Usage:
- * webbench --help
- *
- * Return codes:
- * 0 - sucess
- * 1 - benchmark failed (server is not on-line)
- * 2 - bad param
- * 3 - internal error, fork failed
- *
- */
- #include "socket.c"
- /**
- * 以下是socket.c中的主要代码:
- *
- * //
- * // Socket函数完成的工作:
- * // 1. 转换IP,域名,填充struct sockaddr_in,获取对应的socket描述符;
- * // 2. 连接服务器;
- * //
- *
- * int Socket(const char *host, int clientPort)
- * {
- * //
- * // 局部变量说明:
- * // 1. sock : 用来保存要返回的socket文件描述符;
- * // 2. inaddr : 保存转换为网络序列的二进制数据;
- * // 3. ad : 保存连接网络服务器的地址,端口等信息;
- * // 4. hp : 指向通过gethostbyname()获取的服务器信息;
- * //
- *
- * int sock;
- * unsigned long inaddr;
- * struct sockaddr_in ad;
- * struct hostent *hp;
- *
- * memset(&ad, 0, sizeof(ad));
- * ad.sin_family = AF_INET;
- *
- * //
- * // 这一段主要完成以下功能:
- * // 1. 如果传入的是点分十进制的IP,那么直接转换得到网络字节序列IP;
- * // 2. 如果传入的域名,这需要是用gethostbyname()解析域名获取主机IP;
- * //
- * inaddr = inet_addr(host); //将点分十进制IP转换成网络序列的二进制数据
- * //如果host不是点分十进制的,那么返回INADDR_NONE
- * if (inaddr != INADDR_NONE)
- * memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
- * else
- * {
- * hp = gethostbyname(host);
- * if (hp == NULL)
- * return -1;
- * memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
- * }
- * ad.sin_port = htons(clientPort);
- *
- * //
- * // 这一段主要完成的工作:
- * // 1. 获取socket;
- * // 2. 连接网络服务器;
- * //
- * sock = socket(AF_INET, SOCK_STREAM, 0);
- * if (sock < 0)
- * return sock;
- * if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0)
- * return -1;
- * return sock;
- * }
- *
- */
- #include <unistd.h>
- #include <sys/param.h>
- #include <rpc/types.h>
- #include <getopt.h>
- #include <strings.h>
- #include <time.h>
- #include <signal.h>
- /* values */
- volatile int timerexpired=; //定时器定时到了的标志,子进程根据这个标志退出
- int speed=; //正常响应请求数
- int failed=; //不正常响应请求数
- int bytes=; //从服务器接收返回的数据字节数
- /* globals */
- /**
- * 支持的网络协议,默认是: http/1.0
- * 1. 0 - http/0.9
- * 2. 1 - http/1.0
- * 3. 2 - http/1.1
- */
- int http10=;
- /* Allow: GET, HEAD, OPTIONS, TRACE */
- #define METHOD_GET 0
- #define METHOD_HEAD 1
- #define METHOD_OPTIONS 2
- #define METHOD_TRACE 3
- #define PROGRAM_VERSION "1.5"
- int method = METHOD_GET; //默认请求方式get
- int clients = ; //默认的客户端数量
- int force = ; //连接访问web后是否接收服务器返回的数据
- int force_reload = ; //是否让浏览器缓存页面
- int proxyport = ; //默认代理端口
- char *proxyhost = NULL; //代理主机域名
- /**
- * 默认的测试时间:30s,主要是给子进程的闹钟,时间到了timerexpired会置1,
- * 子进程会根据这个条件退出循环,并通过管道给父进程发送benchtime对应的
- * 时间内对服务器访问的数据:speed,failed,bytes.
- */
- int benchtime = ;
- /* internal */
- /**
- * 父进程与子进程通信通过管道进行通信:
- * 1. mypipe[0] : 是读的管道端口;
- * 2. mypipe[1] : 是写的管道端口;
- */
- int mypipe[];
- /**
- * 存放点分十进制字符串或者域名
- */
- char host[MAXHOSTNAMELEN];
- /*
- * 保存http协议请求头,主要是在build_request()中完成相关操作;
- */
- #define REQUEST_SIZE 2048
- char request[REQUEST_SIZE];
- /**
- * struct option是getopt.h中定义的结构体:
- *
- * struct option
- * {
- * const char *name; //表示长参数名
- *
- * //
- * // # define no_argument 0 //表示该参数后面没有参数
- * // # define required_argument 1 //表示该参数后面一定要跟个参数
- * // # define optional_argument 2 //表示该参数后面可以跟,也可以不跟参数值
- * //
- * int has_arg;
- *
- * //
- * // 用来决定,getopt_long()的返回值到底是什么:
- * // 1. 如果flag是NULL(通常情况),则函数会返回与该项option匹配的val值;
- * // 2. 如果flag不是NULL,则将val值赋予flag所指向的内存,并且返回值设置为0;
- * //
- * int *flag;
- * int val; //和flag联合决定返回值
- * };
- */
- static const struct option long_options[]=
- {
- {"force",no_argument,&force,},
- {"reload",no_argument,&force_reload,},
- {"time",required_argument,NULL,'t'},
- {"help",no_argument,NULL,'?'},
- {"http09",no_argument,NULL,''},
- {"http10",no_argument,NULL,''},
- {"http11",no_argument,NULL,''},
- {"get",no_argument,&method,METHOD_GET},
- {"head",no_argument,&method,METHOD_HEAD},
- {"options",no_argument,&method,METHOD_OPTIONS},
- {"trace",no_argument,&method,METHOD_TRACE},
- {"version",no_argument,NULL,'V'},
- {"proxy",required_argument,NULL,'p'},
- {"clients",required_argument,NULL,'c'},
- {NULL,,NULL,}
- };
- /* prototypes */
- static void benchcore(const char* host,const int port, const char *request);
- static int bench(void);
- static void build_request(const char *url);
- /**
- * alarm_handler函数功能:
- * 1. 闹钟信号处理函数,当时间到了的时候,timerexpired被置1,表示时间到了;
- * 2. benchcore()中会根据timerexpired值来判断子进程的运行;
- *
- */
- static void alarm_handler(int signal)
- {
- timerexpired=;
- }
- /**
- * usage函数功能:
- * 输出webbench的基本是用方法.
- */
- static void usage(void)
- {
- fprintf(stderr,
- "webbench [option]... URL\n"
- " -f|--force Don't wait for reply from server.\n"
- " -r|--reload Send reload request - Pragma: no-cache.\n"
- " -t|--time <sec> Run benchmark for <sec> seconds. Default 30.\n"
- " -p|--proxy <server:port> Use proxy server for request.\n"
- " -c|--clients <n> Run <n> HTTP clients at once. Default one.\n"
- " -9|--http09 Use HTTP/0.9 style requests.\n"
- " -1|--http10 Use HTTP/1.0 protocol.\n"
- " -2|--http11 Use HTTP/1.1 protocol.\n"
- " --get Use GET request method.\n"
- " --head Use HEAD request method.\n"
- " --options Use OPTIONS request method.\n"
- " --trace Use TRACE request method.\n"
- " -?|-h|--help This information.\n"
- " -V|--version Display program version.\n"
- );
- };
- /**
- * main函数完成功能:
- * 1. 解析命令行参数;
- * 2. 组合http请求头;
- * 3. 打印一些初步解析出来的基本信息,用于查看对比信息;
- * 4. 调用bench创建子进程去访问服务器;
- */
- int main(int argc, char *argv[])
- {
- /**
- * 局部变量说明:
- * 1. opt : 返回的操作符;
- * 2. options_index : 当前解析到的长命令行参数的下标;
- * 3. tmp : 指向字符的指针;
- */
- int opt=;
- int options_index=;
- char *tmp=NULL;
- if(argc==)
- {
- usage();
- return ;
- }
- while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF )
- {
- switch(opt)
- {
- case : break;
- case 'f': force=;break; //不接收服务器返回的数据
- case 'r': force_reload=;break; //不缓存请求数据,目前不知有何用
- case '': http10=;break; //选择http/0.9
- case '': http10=;break; //选择http/1.0
- case '': http10=;break; //选择http/1.1
- case 'V': printf(PROGRAM_VERSION"\n");exit(); //返回webbench版本号
- case 't': benchtime=atoi(optarg);break; //设置基准测试时间
- case 'p':
- /* proxy server parsing server:port */
- /**
- * 传入的参数格式:<IP:port>或者<域名:port>,可能的错误有以下3种可能:
- * 1. 传入的参数没有是用:分开IP(或域名)和端口号,包括了没有传参数;
- * 2. 使用了':'号,但是没有给出IP;
- * 3. 使用了':'号,但是没有给出端口号;
- */
- tmp=strrchr(optarg,':');
- proxyhost=optarg;
- if(tmp==NULL)
- {
- break;
- }
- if(tmp==optarg)
- {
- fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg);
- return ;
- }
- if(tmp==optarg+strlen(optarg)-)
- {
- fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg);
- return ;
- }
- /**
- * 将':'换成'\0',这样就得到了IP(或域名)字符串和port字符串,并通过atoi()获取端口号
- */
- *tmp='\0';
- proxyport=atoi(tmp+);break;
- case ':':
- case 'h':
- case '?': usage();return ;break;
- case 'c': clients=atoi(optarg);break; //指定要生成多少个客户端,默认是1个
- }
- }
- /**
- * 命令行参数没有给出URL
- */
- if(optind==argc) {
- fprintf(stderr,"webbench: Missing URL!\n");
- usage();
- return ;
- }
- /**
- * 修正客户端数量和运行时间
- */
- if(clients==) clients=;
- if(benchtime==) benchtime=;
- /* Copyright */
- fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n"
- "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n"
- );
- /**
- * 创建发送给http服务器的请求头
- */
- build_request(argv[optind]);
- /* print bench info */
- /**
- * 接下来这部分都是打印出初步解析出来的数据,可以用来检查是否符合要求
- */
- printf("\nBenchmarking: ");
- switch(method)
- {
- case METHOD_GET:
- default:
- printf("GET");break;
- case METHOD_OPTIONS:
- printf("OPTIONS");break;
- case METHOD_HEAD:
- printf("HEAD");break;
- case METHOD_TRACE:
- printf("TRACE");break;
- }
- printf(" %s",argv[optind]);
- switch(http10)
- {
- case : printf(" (using HTTP/0.9)");break;
- case : printf(" (using HTTP/1.1)");break;
- }
- printf("\n");
- if(clients==)
- printf("1 client");
- else
- printf("%d clients",clients);
- printf(", running %d sec", benchtime);
- if(force)
- printf(", early socket close");
- if(proxyhost!=NULL)
- printf(", via proxy server %s:%d",proxyhost,proxyport);
- if(force_reload)
- printf(", forcing reload");
- printf(".\n");
- /**
- * 调用bench函数,完成相应的功能
- */
- return bench();
- }
- /**
- * build_request函数完成功能:
- * 1. 初始化host和request数组;
- * 2. 检查给出的url参数是否合法;
- * 3. 合成对应http协议的请求头;
- */
- void build_request(const char *url)
- {
- /**
- * 局部变量说明:
- * 1. tmp : 用于存储端口号;
- * 2. i : 循环计数;
- */
- char tmp[];
- int i;
- /**
- * 初始化host和request数组,为下面的操作作准备
- */
- bzero(host,MAXHOSTNAMELEN);
- bzero(request,REQUEST_SIZE);
- /**
- * 不同的请求方式,对应不同的协议标准,这里相当于校正请求协议
- */
- if(force_reload && proxyhost!=NULL && http10<)
- http10=;
- if(method==METHOD_HEAD && http10<)
- http10=;
- if(method==METHOD_OPTIONS && http10<)
- http10=;
- if(method==METHOD_TRACE && http10<)
- http10=;
- switch(method)
- {
- default:
- case METHOD_GET: strcpy(request,"GET");break;
- case METHOD_HEAD: strcpy(request,"HEAD");break;
- case METHOD_OPTIONS: strcpy(request,"OPTIONS");break;
- case METHOD_TRACE: strcpy(request,"TRACE");break;
- }
- strcat(request," ");
- /**
- * url中如果不存在"://"说明是非法的URL地址
- */
- if(NULL==strstr(url,"://"))
- {
- fprintf(stderr, "\n%s: is not a valid URL.\n",url);
- exit();
- }
- /**
- * url字符串长度不能长于1500字节
- */
- if(strlen(url)>)
- {
- fprintf(stderr,"URL is too long.\n");
- exit();
- }
- /**
- * 如果没有设置代理服务器,并且协议不是http,说明出错了.
- */
- if(proxyhost==NULL)
- if (!=strncasecmp("http://",url,))
- {
- fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n");
- exit();
- }
- /* protocol/host delimiter */
- /**
- * 接下来是解析URL并合成请求行
- */
- i=strstr(url,"://")-url+;
- /* printf(" %d\n",i); */ //如果url = "http://www.baidu.com:80/", i = 7
- if(strchr(url+i,'/')==NULL)
- {
- fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n");
- exit();
- }
- /**
- * 这段代码主要完成一下内容:
- * 1. 如果是通过代理服务器对服务器进行访问,那么proxyhost和proxyport就直接
- * 是代理服务器的IP和端口号;
- * 2. 如果是直接访问目标服务器,则需要从URL地址中解析出IP(或者域名)和端口号;
- */
- if(proxyhost==NULL)
- {
- /* get port from hostname */
- if(index(url+i,':')!=NULL &&
- index(url+i,':')<index(url+i,'/'))
- {
- //获取host主机域名
- strncpy(host,url+i,strchr(url+i,':')-url-i);
- //没有给出端口号,就直接是用默认的端口号: 80
- bzero(tmp,);
- strncpy(tmp,index(url+i,':')+,strchr(url+i,'/')-index(url+i,':')-);
- /* printf("tmp=%s\n",tmp); */
- proxyport=atoi(tmp);
- if(proxyport==) proxyport=;
- }
- else
- {
- /**
- * 获取host主机域名,没有给出端口号,就直接是用默认的端口号: 80
- */
- strncpy(host,url+i,strcspn(url+i,"/"));
- }
- // printf("Host=%s\n",host);
- strcat(request+strlen(request),url+i+strcspn(url+i,"/")); //这里是获取URI
- } else
- {
- // printf("ProxyHost=%s\nProxyPort=%d\n",proxyhost,proxyport);
- // 代理服务器需要完整的URL去访问服务器,而不仅仅是URI
- strcat(request,url);
- }
- /**
- * 当前的使用的http协议的版本
- */
- if(http10==)
- strcat(request," HTTP/1.0");
- else if (http10==)
- strcat(request," HTTP/1.1");
- strcat(request,"\r\n");
- /**
- * 到这里请求行就已经合成完毕了,接下来要合成消息头
- */
- if(http10>)
- strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n");
- if(proxyhost==NULL && http10>)
- {
- strcat(request,"Host: ");
- strcat(request,host);
- strcat(request,"\r\n");
- }
- /**
- * 不缓存请求页面,查资料说是对浏览器有效,难道服务器也需要,
- * 不知为何这里也需要?
- */
- if(force_reload && proxyhost!=NULL)
- {
- strcat(request,"Pragma: no-cache\r\n");
- }
- /**
- * 使用短连接,即服务器返回后就断开连接
- */
- if(http10>)
- strcat(request,"Connection: close\r\n");
- /* add empty line at end */
- /**
- * 按不同http协议要求,是否空出一行,下面是请求实体,如果是post请求,
- * 需要把请求参数放在这部分.到这里,消息头也就合成完了,接下
- * 来就是是用这个请求头去访问http服务器了
- */
- if(http10>) strcat(request,"\r\n");
- // printf("Req=%s\n",request);
- }
- /* vraci system rc error kod */
- /**
- * bench函数完成以下功能:
- * 1. 试探性的尝试一次是否能够正常连接服务器,如果连接失败,也就没必要继续后续处理了;
- * 2. 创建管道,用于父子进程通信;
- * 3. 创建clients对应数量的子进程;
- * 4. 子进程:
- * 1. 对服务器进行benchtime秒的连接访问,获取对应的failed,speed,bytes值;
- * 2. 当时间到了benchtime秒以后,打开写管道;
- * 3. 将子进程自己测试得到的failed,speed,bytes值发送给父进程;
- * 4. 关闭写管道文件描述符;
- * 5. 父进程:
- * 1. 打开读管道;
- * 2. 设置管道一些参数,初始化父进程的failed,speed,bytes变量;
- * 3. while循环不断去获取子进程传输过来的数据,直到子进程全部退出;
- * 4. 关闭读管道;
- * 5. 对数据进行处理,并打印输出;
- */
- static int bench(void)
- {
- /**
- * 局部变量说明:
- * 1. i : for循环暂存变量,这里也暂存了一下阿socket文件描述符,
- * 还暂存从子进程传给父进程的speed数据;;
- * 2. j : 暂存从子进程传给父进程的failed数据;
- * 3. k : 暂存从子进程传给父进程的byttes数据;
- * 4. pid : fork()出子进程时,保存进程描述符的;
- * 5. f : 保存打开的管道的文件指针;
- */
- int i,j,k;
- pid_t pid=;
- FILE *f;
- /* check avaibility of target server */
- /**
- * 测试一下我们要测试的服务器是否能够正常连接.
- * Socket函数完成的工作:
- * 1. 转换IP,域名,填充struct sockaddr_in,获取对应的socket描述符;
- * 2. 连接服务器;
- */
- i=Socket(proxyhost==NULL?host:proxyhost,proxyport);
- if(i<) {
- fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");
- return ;
- }
- close(i);
- /* create pipe */
- /**
- * 创建管道,主要用于父进程和子进程通信
- */
- if(pipe(mypipe))
- {
- perror("pipe failed.");
- return ;
- }
- /* not needed, since we have alarm() in childrens */
- /* wait 4 next system clock tick */
- /*
- cas=time(NULL);
- while(time(NULL)==cas)
- sched_yield();
- */
- /* fork childs */
- for(i=;i<clients;i++)
- {
- pid=fork();
- /**
- * 子进程获取到的pid=0,所以子进程会理解跳出循环
- * 不会再创建子进程,而父进程则会跳过这个判断,继续
- * 创建子进程,知道数量达到clients的值.
- */
- if(pid <= (pid_t) )
- {
- /* child process or error*/
- sleep(); /* make childs faster */
- break;
- }
- }
- //创建子进程失败
- if( pid< (pid_t) )
- {
- fprintf(stderr,"problems forking worker no. %d\n",i);
- perror("fork failed.");
- return ;
- }
- /**
- * 这一部分完成的工作:
- * 1. 子进程:
- * 1. 对服务器进行benchtime秒的连接访问,获取对应的failed,speed,bytes值;
- * 2. 当时间到了benchtime以后,打开写管道;
- * 3. 将子进程自己测试得到的failed,speed,bytes值发送给父进程;
- * 4. 关闭写管道文件描述符;
- * 2. 父进程:
- * 1. 打开读管道;
- * 2. 设置管道一些参数,初始化父进程的failed,speed,bytes变量;
- * 3. while循环不断去获取子进程传输过来的数据,直到子进程全部退出;
- * 4. 关闭读管道;
- * 5. 对数据进行处理,并打印输出;
- */
- if(pid== (pid_t) )
- {
- /* I am a child */
- if(proxyhost==NULL)
- benchcore(host,proxyport,request);
- else
- benchcore(proxyhost,proxyport,request);
- /* write results to pipe */
- f=fdopen(mypipe[],"w");
- if(f==NULL)
- {
- perror("open pipe for writing failed.");
- return ;
- }
- /* fprintf(stderr,"Child - %d %d\n",speed,failed); */
- fprintf(f,"%d %d %d\n",speed,failed,bytes);
- fclose(f);
- return ;
- }
- else
- {
- f=fdopen(mypipe[],"r");
- if(f==NULL)
- {
- perror("open pipe for reading failed.");
- return ;
- }
- setvbuf(f,NULL,_IONBF,); //设置管道为无缓冲类型
- speed=;
- failed=;
- bytes=;
- while()
- {
- pid=fscanf(f,"%d %d %d",&i,&j,&k);
- if(pid<)
- {
- fprintf(stderr,"Some of our childrens died.\n");
- break;
- }
- speed+=i;
- failed+=j;
- bytes+=k;
- /* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); */
- if(--clients==) break;
- }
- fclose(f);
- printf("\nSpeed=%d pages/min, %d bytes/sec.\nRequests: %d susceed, %d failed.\n",
- (int)((speed+failed)/(benchtime/60.0f)),
- (int)(bytes/(float)benchtime),
- speed,
- failed);
- }
- return i;
- }
- /**
- * benchcore函数完成功能:
- * 1. 注册闹钟处理函数,设置闹钟时间,具体时间由benchtime给出,默认是30s;
- * 2. while循环里判断闹钟时间是否到了,如果到了退出循环;
- * 3. while循环里连接服务器;
- * 4. while循环里发送http请求头给服务器;
- * 5. while循环里判断是否需要接受服务器数据;
- * 6. 关闭与服务器的连接;
- * 7. 在整个过程中,以下变量会统计在benchtime给出的时间内的一些信息:
- * 1. failed : 连接服务器失败和传输数据过程中失败的连接数;
- * 2. speed : 正常连接服务器,并且正常传输数据的连接数
- * 3. bytes : 从服务器获取到的字节数;
- */
- void benchcore(const char *host,const int port,const char *req)
- {
- /**
- * 局部变量说明:
- * 1. rlen : 请求字符串的长度;
- * 2. buf : 保存从服务器获取的数据;
- * 3. s : socket文件描述符;
- * 4. i : 保存从服务器读到的字节数;
- * 5. sa : 信号结构体变量;
- */
- int rlen;
- char buf[];
- int s,i;
- struct sigaction sa;
- /* setup alarm signal handler */
- /**
- * 注册闹钟信号处理函数,并设置闹钟时间为benchtime,默认是30s;
- */
- sa.sa_handler=alarm_handler;
- sa.sa_flags=;
- if(sigaction(SIGALRM,&sa,NULL))
- exit();
- alarm(benchtime);
- rlen=strlen(req);
- nexttry:
- while()
- {
- if(timerexpired) //检查闹钟时间是否到了,如果到了,子进程就退出
- {
- if(failed>)
- {
- /* fprintf(stderr,"Correcting failed by signal\n"); */
- failed--;
- }
- return;
- }
- s=Socket(host,port);
- if(s<)
- {
- failed++;
- continue;
- }
- /**
- * 将请求头发给web服务器
- */
- if(rlen!=write(s,req,rlen))
- {
- /**
- * 写数据失败,代表当前连接有问题,也就是失败了
- */
- failed++;
- close(s);
- continue;
- }
- if(http10==) // http/0.9协议
- if(shutdown(s,))
- {
- failed++;
- close(s);
- continue;
- }
- if(force==) //是否读取服务器返回数据
- {
- /* read all available data from socket */
- while()
- {
- if(timerexpired) break; //判断是否已经闹钟到时
- i=read(s,buf,);
- /* fprintf(stderr,"%d\n",i); */
- /**
- * 对当前次连接数据读取错误,那么重来
- */
- if(i<)
- {
- failed++;
- close(s);
- goto nexttry;
- }
- else
- if(i==)
- break;
- else
- bytes+=i; //统计一共读取了多少字节
- }
- }
- /**
- * 关闭socket文件,如果出错,那么增加失败的统计数据
- */
- if(close(s))
- {
- failed++;
- continue;
- }
- /**
- * 成功完成连接,数据传输,获取等等工作,speed统计数据+1
- */
- speed++;
- }
- }
webbench-1.5_hacking的更多相关文章
- Webbench性能测试
1.下载安装:立即下载 官网:http://home.tiscali.cz/~cz210552/webbench.html 2.解压缩:tar -zxvf webbench-1.5.tar.gz 3 ...
- webbench之使用(二)
[root@lam7 ~]# webbench -helpwebbench [option]... URL -f|--force Don't wait for reply ...
- webbench之编译安装(一)
1.编译安装: 1 2 3 4 [root@hexuweb102 ~]$wget http://blog.s135.com/soft/linux/webbench/webbench-1.5.tar ...
- Linux下四款Web服务器压力测试工具(http_load、webbench、ab、siege)介绍
一.http_load程序非常小,解压后也不到100Khttp_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载.但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般不会把 ...
- linux下如何安装webbench
1.上传webbench,解压 2.make&&make install进行安装 如果报没有man1目录,则要用 mkdir -p /usr/local/man/man1 然后 mak ...
- 网站压力测试工具webbench使用说明
一.webbench简介 Webbench是有名的网站压力测试工具,它是由Lionbridge公司(http://www.lionbridge.com)开发.它的帮助文件和文档请到:ww ...
- WebBench源码分析与心得
源码:https://github.com/EZLippi/WebBench 关键全局变量: speed 成功次数 failed 失败次数 bytes 接收字节数 benchtime 执行时长(秒 ...
- webbench 压力测试
原文 webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好用,安装使用也特别方便,并且非常小. 主要是 -t 参数用着比较爽,下面参考了张宴 ...
- 压力测试 webbench
Linux下 webbench最多可以模拟3万个并发连接去测试网站的负载能力 webbench -c -t http://127.0.0.1/phpinfo.php 说明: -c 客户端数量(并发数量 ...
随机推荐
- jekins 实现Django项目的自动部署(ubuntu16.04,python2.7,django1.11)
1.依赖的插件 如果插件下载失败 更换源 http://mirror.xmission.com/jenkins/updates/current/update-center.json 因为我们只需要构建 ...
- 【转】VMware网络连接模式—桥接、NAT以及仅主机模式的详细介绍和区别
☞ 本文主要介绍软件『VMware Workstation(虚拟机)』的相关内容:VMware网络连接模式—桥接.NAT以及仅主机模式的详细介绍和区别. 其下列版本/分支可以参考本文: 全部版本/分支 ...
- 装B必备之 快捷键配置
作为一个程序员 所有程序都用快捷来这是装B必备的无形装B 最为致命.... 开始搞起 第一步配置环境变量 在系统D盘新建一个文件夹 D:\cache; 然后把这个路径 配置上 D:\cache; 最 ...
- zlib__ZC
官网:http://www.zlib.net/ ,所有版本下载:http://www.zlib.net/fossils/ ZC: 我下载的是 zlib-1.2.3.tar.gz 和 zlib-1.2. ...
- SpringBoot中的数据库连接池
内置的连接池 目前Spring Boot中默认支持的连接池有dbcp,dbcp2, tomcat, hikari三种连接池. 数据库连接可以使用DataSource池进行自动配置. 由于Tomcat数 ...
- 各种容器与服务器的区别与联系 Servlet容器 WEB容器 Java EE容器 应用服务器 WEB服务器 Java EE服务器
转自:https://blog.csdn.net/tjiyu/article/details/53148174 各种容器与服务器的区别与联系 Servlet容器 WEB容器 Java EE容器 应用服 ...
- 秒杀多线程第六篇 经典线程同步 事件Event
原文地址:http://blog.csdn.net/morewindows/article/details/7445233 上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权” ...
- 最齐全的Android studio 快捷键(亲测可用)
Action Mac OSX Win/Linux 注释代码(//) Cmd + / Ctrl + / 注释代码(/**/) Cmd + Option + / Ctrl + Alt + / 格式化代码 ...
- 使用poi导出Excel,并设定单元格内容类型,抛出异常
本例子使用的是HSSF,为Excel2003提供处理方案. 设定为输入类型为数值 import org.apache.poi.hssf.usermodel.DVConstraint; import o ...
- JavaWeb重定向和转发
if (user != null && passWord.equals(user.getPassWord())) { // 登录成功 // response.sendRedirect( ...