/****************************************************************************
*
* 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的更多相关文章

  1. Webbench性能测试

    1.下载安装:立即下载  官网:http://home.tiscali.cz/~cz210552/webbench.html 2.解压缩:tar -zxvf webbench-1.5.tar.gz 3 ...

  2. webbench之使用(二)

    [root@lam7 ~]# webbench -helpwebbench [option]... URL -f|--force                Don't wait for reply ...

  3. webbench之编译安装(一)

    1.编译安装:   1 2 3 4 [root@hexuweb102 ~]$wget http://blog.s135.com/soft/linux/webbench/webbench-1.5.tar ...

  4. Linux下四款Web服务器压力测试工具(http_load、webbench、ab、siege)介绍

    一.http_load程序非常小,解压后也不到100Khttp_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载.但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般不会把 ...

  5. linux下如何安装webbench

    1.上传webbench,解压 2.make&&make install进行安装 如果报没有man1目录,则要用 mkdir -p /usr/local/man/man1 然后 mak ...

  6. 网站压力测试工具webbench使用说明

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

  7. WebBench源码分析与心得

    源码:https://github.com/EZLippi/WebBench   关键全局变量: speed 成功次数 failed 失败次数 bytes 接收字节数 benchtime 执行时长(秒 ...

  8. webbench 压力测试

    原文 webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好用,安装使用也特别方便,并且非常小. 主要是 -t 参数用着比较爽,下面参考了张宴 ...

  9. 压力测试 webbench

    Linux下 webbench最多可以模拟3万个并发连接去测试网站的负载能力 webbench -c -t http://127.0.0.1/phpinfo.php 说明: -c 客户端数量(并发数量 ...

随机推荐

  1. Seleniumz中 dr.quit()和dr.close()的区别

    /** * dr.quit()和dr.close()都可以退出浏览器,简单的说一下两者的区别:第一个close, * 如果打开了多个页面是关不干净的,它只关闭当前的一个页面.第二个quit, * 是退 ...

  2. 爱阅app --- 答复功能改进建议

    共有四组评论,接下来一一答复. 第一组: 希望增加的功能: 1.希望能够继续完善书签功能,增加逐条删除书签功能. 2.能够在爱阅内部打开APP中提供的网址,用户选择一款阅读APP,当然不想每看一本新的 ...

  3. C# DataTable列名不区分大小写

    一直很纠结的就是DataTable的列名如何才能规范,从Oracle取出的DataTable都是大写,最后尝试了一下,原来C#的DataTable列名并不区分大小写,具体例子如下: DataTable ...

  4. 你的centos/linux下有多个php.ini,不确定是哪个时

    你的centos/linux下有多个php.ini,不确定是哪个时,但是你自己知道,你的php安装目录. 比如我的php安装目录是 /usr/local/php 那么可以通过命令来查找php.ini的 ...

  5. 雷林鹏分享:Ruby 方法

    Ruby 方法 Ruby 方法与其他编程语言中的函数类似.Ruby 方法用于捆绑一个或多个重复的语句到一个单元中. 方法名应以小写字母开头.如果您以大写字母作为方法名的开头,Ruby 可能会把它当作常 ...

  6. 使用Jenkins实现maven项目一键部署

    下面的博客请详细的,值得一看:jenkins+maven+svn实现简单的一键发布 http://blog.csdn.net/pein_zero/article/details/52597615#co ...

  7. 20170728xlVba简单的匹配

    Sub MatchData() Dim i As Long, EndRow As Long, Key As String Dim Rng As Range Dim Dic As Object Set ...

  8. 20170706wdVBA正则表达式提取题目

    Public Sub GetContents() Dim Reg As Object Dim Matches As Object Dim OneMatch As Object Dim Index As ...

  9. Many Easy Problem

    转自hwk0518,不胜感谢,侵删.

  10. ubuntu mysql主从库的搭建

    1,首先我们要确定一个从库一个主库,紧记从库只能读取不能有其他的操作,如果操作写那主从就失效了,那就看看我们这么搭建主从吧! 2. 环境:Ubuntu,Mysql (主从的数据库版本必须保持一致) 主 ...