Ubuntu 下安装使用

1、安装依赖包CTAGS

sudo apt-get install ctage

2、下载及安装 Webbench

http://home.tiscali.cz/~cz210552/webbench.html

解压:

tar -zxvf webbench-1.5.tar.gz

切换到解压后的目录:

cd webbench-1.5

编译:

make

安装:

sudo make install

webbench使用

#webbench -? (查看命令帮助)

常用参数 说明,-c 表示客户端数,-t 表示时间

./webbench -c 500 -t 30 http://xyzp.xaut.edu.cn/Plugins/YongHu_plug/Pages/loginbysjy.aspx

代码学习:

众所周知,C程序的主函数有两个参数,其中第一个参数是整数,可以获得包括程序名字的参数个数,第二个参数是字符数组或字符指针的指针,可以按顺序获得命令行上各个字符串的参数。其原型是:

int main(int argc, char const *argv[])

或者

int main(int argc, char const **argv)

有鉴于此,在Unix和Linux的正式项目上,程序员通常会使用getopt()或者getopt_long()来获得输入的参数。两者的区别在于getopt()仅支持短格式参数,而getopt_long()既支持短格式参数,也支持长格式参数。

./webbench -V

1.5

./webbench --version

1.5

关于getopt_long()的具体用法参考:man getopt_long

在处理命令行参数时,用到一个变量 optind, 原来是系统定义的。

可以在命令行中,通过 man optind 来看相关信息

optind: the index of the next element to be processed in the argv.  The system initializes it to 1. The caller can reset it to 1 to restart scanning of the same argv or scanning a new argument vector.

当调用 getopt() , getopt_long() 之类的函数时, optind 的值会变化。如:

执行 $  ./a.out -ab         当调用  一次  getopt() , 则 optind 值会 +1

进程间通信的方式之管道:管道分为无名管道(匿名管道)和命名管道

使用无名管道,则是通信的进程之间需要一个父子关系,通信的两个进程一定是由一个共同的祖先进程启动。但是无名管道没有数据交叉的问题。

使用命名管道可以解决无名管道中出现的通信的两个进程一定是由通一个共同的祖先进程启动的问题,但是为了数据的安全,很多时候要采用阻塞的FIFO,让写操作变成原子操作。

只有两个源文件:webbench.c, socket.c。
 /* $Id: socket.c 1.1 1995/01/01 07:11:14 cthuang Exp $
*
* This module has been modified by Radim Kolar for OS/2 emx
*/ /***********************************************************************
module: socket.c
program: popclient
SCCS ID: @(#)socket.c 1.5 4/1/94
programmer: Virginia Tech Computing Center
compiler: DEC RISC C compiler (Ultrix 4.1)
environment: DEC Ultrix 4.3
description: UNIX sockets code.
***********************************************************************/ #include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> /*
根据通信地址和端口号建立网络连接
@host:网络地址
@clientPort:端口号
成功返回建立连接套接字
建立套接字失败返回-1
*/
int Socket(const char *host, int clientPort)
{
int sock;
unsigned long inaddr;
struct sockaddr_in ad;
struct hostent *hp; memset(&ad, , sizeof(ad));
ad.sin_family = AF_INET;
//将点分十进制的IP地址转化为无符号的长整形
inaddr = inet_addr(host);
if (inaddr != INADDR_NONE)
memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
else
{
//如果host是域名,则通过域名获取IP地址
hp = gethostbyname(host);
if (hp == NULL)
return -;
memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
}
ad.sin_port = htons(clientPort); sock = socket(AF_INET, SOCK_STREAM, );
if (sock < )
return sock;
if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < )
return -;
return sock;
}

socket.c

 
 /*
* (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"
#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 */
int http10=; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */
/* 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;
int clients=;
int force=;
int force_reload=;
int proxyport=;
char *proxyhost=NULL;
int benchtime=;
/* internal */
int mypipe[]; //主机名的最大长度通常是由头文件<sys/param.h>定义的常值MAXHOSTNAMELEN
char host[MAXHOSTNAMELEN];
#define REQUEST_SIZE 2048
char request[REQUEST_SIZE]; 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); static void alarm_handler(int signal)
{
timerexpired=;
} 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"
);
}; int main(int argc, char *argv[])
{
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;
case '': http10=;break;
case '': http10=;break;
case 'V': printf(PROGRAM_VERSION"\n");exit();
case 't': benchtime=atoi(optarg);break;
case 'p':
/* proxy server parsing server:port */
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 ;
}
*tmp='\0';
proxyport=atoi(tmp+);
break;
case ':':
case 'h':
case '?':
usage();
return ;
break;
case 'c':
clients=atoi(optarg);
break;
}
} //判断命令行参数是否解析完成,如果完成代表没有需要访问的超链接
//optind的值随着调用getopt_long次数改变,每调用一次加一
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"); build_request(argv[optind]); //对设置参数的一些显示信息
/* print bench info */
printf("\n Bench marking: "); 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.0)");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"); return bench();
}
/*
*输入URL的连接
*解析URl,构造请求头并且将请求头,
*保存到全局变量request中
GET /Plugins/YongHu_plug/Pages/loginbysjy.aspx HTTP/1.0
User-Agent: WebBench 1.5
Host: xyzp.xaut.edu.cn
*/
void build_request(const char *url)
{
char tmp[];
int i;
//清空存储区
bzero(host,MAXHOSTNAMELEN);
bzero(request,REQUEST_SIZE);
//force_reload不等待响应,强制刷新
//proxyhost是否设置了代理
//判断是否设置了Http的通信协议版本
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," "); //判断Http请求的地址正确性以及有效性
if(NULL==strstr(url,"://"))
{
fprintf(stderr, "\n%s: is not a valid URL.\n",url);
exit();
}
if(strlen(url)>)
{
fprintf(stderr,"URL is too long.\n");
exit();
} if(proxyhost==NULL)
{
if (!=strncasecmp("http://",url,))
{
fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n");
exit();
}
}
//跳过超链接的协议头,找到顶级域名
/* protocol/host delimiter */
i=strstr(url,"://")-url+;
/* printf("%d\n",i); */ //跳过顶级域名
if(strchr(url+i,'/')==NULL)
{
fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n");
exit();
}
if(proxyhost==NULL)
{
//获取指定的通信端口,如果不存在则使用默认的80端口,同时获得主机名称-域名,网页的绝对路径
/* get port from hostname */
if(index(url+i,':')!=NULL &&
index(url+i,':')<index(url+i,'/'))
{
strncpy(host,url+i,strchr(url+i,':')-url-i);
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
{
strncpy(host,url+i,strcspn(url+i,"/"));
}
//printf("Host=%s\n",host);
strcat(request+strlen(request),url+i+strcspn(url+i,"/"));
}
else
{
// printf("ProxyHost=%s\nProxyPort=%d\n",proxyhost,proxyport);
strcat(request,url);
}
//设置请求协议的版本,拼接请求头
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 */
if(http10>)
{
strcat(request,"\r\n");
}
//printf("Req=%s\n",request);
} /* vraci system rc error kod */
static int bench(void)
{
int i,j,k;
pid_t pid=;
FILE *f; /* check avaibility of target server */
//测试远程主机的是否可用
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++)
{
/*
调用fork有一个特殊的地方,就是调用一次却能返回两次,有三种不同的返回值:
1、在父进程中,fork返回新创建的子进程的进程ID
2、在子进程中,fork返回0
3、如果出现错误,fork返回一个负值
*/
pid=fork();
if(pid <= (pid_t) )
{
/* child process or error*/
sleep(); /* make childs faster */
/*这个break很重要,它主要让子进程只能从父进程生成,
否则子进程会在创建子进程,子子孙孙无穷尽*/
break;
}
} if( pid< (pid_t) )
{
fprintf(stderr,"problems forking worker no. %d\n",i);
perror("fork failed.");
return ;
} 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;
} void benchcore(const char *host,const int port,const char *req)
{
int rlen;
char buf[];
int s,i;
struct sigaction sa; /* setup alarm signal handler */
//这个是关键,当程序执行到指定的秒数之后,发送 SIGALRM 信号
sa.sa_handler=alarm_handler;
sa.sa_flags=;
if(sigaction(SIGALRM,&sa,NULL))
{
exit();
} alarm(benchtime); rlen=strlen(req);
//无限执行请求,并发操作,直到接收到 SIGALRM 信号将 timerexpired 设置为 1 时
nexttry:while()
{
if(timerexpired)
{
if(failed>)
{
/* fprintf(stderr,"Correcting failed by signal\n"); */
failed--;
}
return;
}
//连接服务器
s=Socket(host,port);
if(s<)
{
failed++;
continue;
}
//发送请求头
if( rlen!=write(s,req,rlen) )
{
failed++;
close(s);
continue;
} if(http10==)
{
//如果是 http/0.9 则关闭socket的写操作
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;
}
}
}
//关闭连接,执行下一次请求
if(close(s))
{
failed++;
continue;
}
//记录请求成功的次数
speed++;
}
}

网站压力测试工具-Webbench源码笔记的更多相关文章

  1. LINUX下一款不错的网站压力测试工具webbench

    LINUX下一款不错的网站压力测试工具webbench 分类: Linux 2014-07-03 09:10 220人阅读 评论(0) 收藏 举报 [html] view plaincopy wget ...

  2. LINUX 的网站压力测试工具 webbench

    网站压力测试工具-Webbench webbench简介:        Webbench是有名的网站压力测试工具,它是由 Lionbridge公司(http://www.lionbridge.com ...

  3. linux 下网站压力测试工具webbench

    一直在用webbench ,这个linux下的网站压力测试工具.整理下. 笔记本装的ubuntu,其他linux系统也差不多. webbench 需要先安装 ctags,一个vim的阅读插件,可以直接 ...

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

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

  5. 找到一款不错的网站压力测试工具webbench

    webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便. 1.适用系统:Linux 2.编译安装: 引用 wget htt ...

  6. 网站压力测试工具webbench

    webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便. 1.适用系统:Linux 2.编译安装: 引用 wget htt ...

  7. tony_linux下网站压力测试工具webbench

    webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便. 1.适用系统:Linux 2.编译安装:wget http:// ...

  8. 网站压力测试工具webbench 安装与使用

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

  9. 网站压力测试 工具webbench

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

随机推荐

  1. Data Flow ->> Term Extraction

    中文意思是关键词抽取,用于计算在文本中哪些词汇或者词组出现的频率最高.其实算法有两张:1)Frequency 2)TFIDF TFIDF的全称是Term Frequency and Inverse D ...

  2. Line Search and Quasi-Newton Methods 线性搜索与拟牛顿法

    Gradient Descent 机器学习中很多模型的参数估计都要用到优化算法,梯度下降是其中最简单也用得最多的优化算法之一.梯度下降(Gradient Descent)[3]也被称之为最快梯度(St ...

  3. vim快捷键笔记【原创】

    Vim zR  全部展开 zM全部合并 vim  快捷键 shift   +  i      (‘I’)    进行编辑 shift   +  4     (‘$’)    跳到行尾 shift   ...

  4. Spring 注解@Transactional

    Spring事务的传播行为 在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例 ...

  5. MyEclipse 10离线安装PyDev插件

    PyDev for Eclipse, 经过测试,一般在线安装会失败(不能访问某些网站所致) 以下为离线安装步骤 1 下载 PyDev 2.8.2,  链接:http://sourceforge.net ...

  6. HeadFirst Jsp 04 (请求和响应作为servlet)

    servlet 的存在就是为了客服服务, servlet的任务是得到一个客户的请求, 再发回一个响应. 由上图可知, web 容器会在启动后就加载所有的servlet类, 并为之创建实例和初始化 注意 ...

  7. 导出excel小结(C#,.NET,Wpf)

    range.NumberFormatLocal = "@";     //设置单元格格式为文本      range.NumberFormatLocal = "@&quo ...

  8. Android Studio插件

    awesome-android-ui(UI范例库) https://github.com/wasabeef/awesome-android-ui/tree/master/pages LMBanners ...

  9. SPOJ ARCTAN (数论) Use of Function Arctan

    详细的题解见这里. 图片转自上面的博客 假设我们已经推导出来x在处取得最小值,并且注意到这个点是位于两个整点之间的,所以从这两个整数往左右两边枚举b就能找到b+c的最小值. 其实只用往一边枚举就够了, ...

  10. POJ 3261 (后缀数组 二分) Milk Patterns

    这道题和UVa 12206一样,求至少重复出现k次的最长字串. 首先还是二分最长字串的长度len,然后以len为边界对height数组分段,如果有一段包含超过k个后缀则符合要求. #include & ...