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. Java:装饰设计模式

    装饰设计模式: 当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能, 并提供加强功能,那么自定义的该类就称为装饰类. 装饰类通常通过构造方法接收被装饰的对象,并基于被装饰的对 ...

  2. 浅析CSS负边距

    本文主要讨论两点,1.左右负边距对元素宽度的影响:2.负边距对浮动元素的影响. 在讨论这两点前,首先要理解盒模型.文档流. 盒模型,见下图,简单明了. 文档流,将窗体自上而下分成一行行, 并在每行中按 ...

  3. Android开发实例详解之IMF(Android SDK Sample—SoftKeyboard)

    本博前面的文章介绍了Android开发环境的搭建和模拟器的常用操作.本次,将以Android Sample中经典的SoftKeyboard项目为例,详细解析Android上一个小型项目的开发过程和注意 ...

  4. 纯java从apk文件里获取包名、版本号、icon

    简洁:不超过5个java文件 依赖:仅依赖aapt.exe 支持:仅限windows 功能:用纯java获取apk文集里的包名,版本号,图标文件[可获取到流直接保存到文件系统] 原理:比较上一篇文章里 ...

  5. 4.cadence原理图,环境设置[原创]

    1.菜单介绍 创建工程,原理图纸 特殊点: 鼠标先点击1,,在选中1后点击2 在Tools菜单下 Annotate:自动编号 back Annotate: 回标 -- DRC规则检测 Create N ...

  6. 堆的 两种实现 (数组和STL)

    基本思想: 两种操作都跟树的深度成正比,所以复杂度  O(log(n)) ; push():在向堆中插入数值时,首先在堆的末尾插入该数值,然后不断向上提直到没有大小颠倒为止. pop(): 从堆中取出 ...

  7. 总结Selenium自动化测试方法(三)WebDriver定位元素方法

    三.WebDriver定位元素 推荐使用的webdriver是firefox,因为他的firebug更能可以帮助定位页面元素使用 # create a new Firefox session cls. ...

  8. 警惕rapidxml的陷阱:添加节点时,请保证变量的生命周期

    http://www.cnblogs.com/chutianyao/p/3246592.html 项目中要使用xml打包.解析协议,HQ指定了使用rapidxml--号称是最快的xml解析器. 功能很 ...

  9. Spring+Hibernate配置多数据源

    配置说明 在实际应用中,经常会用到读写分离,这里就这种情况进行Spring+Hibernate的多数据源配置.此处的配置只是让读的方法操作一个数据库,写的方法操作另外一个数据库. 注:我这里的配置JD ...

  10. Python3 学习第十一弹: 模块学习四之sys库

    sys模块 提供一些与python解释器关系紧密的变量和函数 1> argv 命令行参数 通过命令行可以向python传输参数 2> exit([arg]) 程序退出,可以返回给命令行一个 ...