webbench源码浅析
下载webbench:http://home.tiscali.cz/~cz210552/webbench.html,最近更新时间是04年的6月25号!!!
解压后的webbench由下面几个文件组成:
其中有2个C源文件,一个是socket.c 另一个是webbench.c
socket.c
- 内部仅包含一个Socket函数,如下:
- int Socket(const char *host, int clientPort)
- {
-
//以host和clientPort构成一对TCP的套接字(服务器)
-
//创建失败返回-1 成功返回一个sockt描述符
- }
- 在webbench.c源文件中,包含了下面几个函数:
- static void alarm_handler(int signal)
- static void usage(void)
- void build_request(const char *url)
- static int bench(void)
- void benchcore(const char *host, const int port, const char *req)
- 当然还有main函数 int main(int argc, char *argv[])
- 这里先对全局变量做一下说明
-
/* values */
volatile int timerexpired=0; //根据命令行参数-t指定的测试时间判断是否超时
int speed=0; //子进程成功得到服务器响应的总数
int failed=0; //子进程请求失败总数
int bytes=0; //读取到的字节数
/* globals */
int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */ //HTTP协议版本定义
/* 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; //定义HTTP请求方法GET 此外还支持OPTIONS、HEAD、TRACE方法,在main函数中用switch判断
int clients=1; //默认并发数为1,也就是子进程个数 可以由命令行参数-c指定
int force=0; //是否等待从服务器获取数去数据 0为获取
int force_reload=0; //是否使用cache 0为使用
int proxyport=80; //代理服务器端口 80
char *proxyhost=NULL; //代理服务器IP 默认为NULL
int benchtime=30; //测试时间 默认为30秒 可由命令行参数-t指定
/* internal */
int mypipe[2]; //创建管道(半双工) 父子进程间通信,读取/写入数据
char host[MAXHOSTNAMELEN]; //定义服务器IP
#define REQUEST_SIZE 2048
char request[REQUEST_SIZE]; //HTTP请求信息
- /* vraci system rc error kod */
- static int bench(void)
- {
- int i,j,k;
- pid_t pid=0;
- FILE *f;
- /* check avaibility of target server */
- i=Socket(proxyhost==NULL?host:proxyhost,proxyport); //判断是否使用代理服务器,将Socket函数的返回值进行判断
- if(i<0) { //错误处理
-
fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");
return 1;
- }
- close(i);
- /* create pipe */
- if(pipe(mypipe)) //创建管道及错误处理
- {
- perror("pipe failed.");
- return 3;
- }
- /* 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=0;i<clients;i++) //根据clients大小fork出子进程,fork函数有两个返回值,在子进程中返回值为0;在父进程中返回值为新创建子进程的pid;可以根据fork的返回值,判断当前进程是父进程还是子进程
- {
- pid=fork();
- if(pid <= (pid_t) 0)
- {
- /* child process or error*/
- sleep(1); /* make childs faster */
- break;
- }
- }
- if( pid< (pid_t) 0) //错误处理,fork调用失败返回负数
- {
- fprintf(stderr,"problems forking worker no. %d\n",i);
- perror("fork failed.");
- return 3;
- }
- if(pid== (pid_t) 0) //判断pid是否为0,为0则进入子进程执行相应的代码
- {
- /* I am a child */
- if(proxyhost==NULL) //判断代理,进入benchcore函数
- benchcore(host,proxyport,request);
- else
- benchcore(proxyhost,proxyport,request);
- /* write results to pipe */
- f=fdopen(mypipe[1],"w"); //打开管道,子进程往管道写数据
- if(f==NULL) //错误处理
- {
- perror("open pipe for writing failed.");
- return 3;
- }
- /* fprintf(stderr,"Child - %d %d\n",speed,failed); */
- fprintf(f,"%d %d %d\n",speed,failed,bytes); //往管道写数据
- fclose(f);
- return 0;
- } else //判断pid是否大于0,大于0进入父进程,执行相应代码
- {
- f=fdopen(mypipe[0],"r"); //打开管道,父进程从管道读数据,一个管道只能进行半双工的工作(一端读,一端写)
- if(f==NULL)
- {
- perror("open pipe for reading failed.");
- return 3;
- }
- setvbuf(f,NULL,_IONBF,0);
- speed=0;
- failed=0;
- bytes=0;
- while(1)
- {
- pid=fscanf(f,"%d %d %d",&i,&j,&k); //从管道读数据
- if(pid<2)
- {
- fprintf(stderr,"Some of our childrens died.\n");
- break;
- }
- speed+=i; //全局计数器 speed failed bytes
- failed+=j;
- bytes+=k;
- /* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); */
- if(--clients==0) break; //子进程为0,数据读完后,退出循环
- }
- 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[1500];
- int s,i;
- struct sigaction sa;
- /* setup alarm signal handler */
- sa.sa_handler=alarm_handler; //加载信号处理函数
- sa.sa_flags=0;
- if(sigaction(SIGALRM,&sa,NULL))
- exit(3);
- alarm(benchtime); //计时开始
- rlen=strlen(req);
- nexttry:while(1) //带go-to语句的while循环
- {
- if(timerexpired) //超时则退出函数
- {
- if(failed>0)
- {
- /* fprintf(stderr,"Correcting failed by signal\n"); */
- failed--;
- }
- return;
- }
- s=Socket(host,port); //建立socket连接,获取socket描述符
- if(s<0) { failed++;continue;} //连接建立失败,failed++
- if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;} //往服务器发送请求;如果请求失败,failed++,关闭当前子进程socket描述符,go-to到while循环再来一次
- if(http10==0) //针对HTTP0.9的处理办法
- if(shutdown(s,1)) { failed++;close(s);continue;}
- if(force==0) //判断是否从服务器读取数据
- {
- /* read all available data from socket */
- while(1)
- {
- if(timerexpired) break; //判断超时
- i=read(s,buf,1500); //从服务器读取数据,保存到buff数组中
- /* fprintf(stderr,"%d\n",i); */
- if(i<0) //读取数据失败的处理,返回while循环开始处,重新来一次
- {
- failed++;
- close(s);
- goto nexttry;
- }
- else
- if(i==0) break; //读取成功后,bytes统计数据大小
- else
- bytes+=i;
- }
- }
- if(close(s)) {failed++;continue;}
- speed++;
- }
- }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。