【webbench】源码剖析

来源:互联网 发布:php 最好的编程语言 编辑:程序博客网 时间:2024/05/16 23:44

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>int Socket(const char *host, int clientPort){int sock;unsigned long inaddr;/***************************************  struct sockaddr_in{short int sin_family  //协议族,只能是AF_INETunsigned short int sin_port //端口号struct in_addr sin_addr;    //IP地址unsigned char sin_zero[8];  //保持sockaddr_in和sockaddr一致  };  struct in_addr{unsigned long s_addr;    //按照网络字节顺序存储IP地址  };  **************************************/struct sockaddr_in ad;struct hostent *hp;/****************************************struct hostent{  char  *h_name;     //主机名,官方域名  char **h_aliases;  //主机所有别名  int    h_addrtype; //IP地址类型  int    h_length;   //IP地址长度  char **h_addr_list;//IP地址,网络字节序};struct hostent *gethostbyname(const char * hostname);  **************************************//*=== 设置sockaddr_in ===*//* 初始化地址 */memset(&ad, 0, sizeof(ad));/*set---sin_family*/ad.sin_family = AF_INET;/*set---sin_addr*//* 将IP地址转换为长整型,如果是.分隔的ip,如:192.168.22.30 */inaddr = inet_addr(host);if(inaddr != INADDR_NONE) //有效地址memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));/* 如果是字符串格式的,如:www.baidu.com,用gethostbyname()*/else{hp = gethostbyname(host);if(hp == NULL)return -1;/* hostent中的*h_addr是h_addr_list[0] */memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);}/*set---sin_port*//* htons将无符号整型转换为网络字节序 */ad.sin_port = htons(clientPort);/*==== 创建socket套接字,连接 ====*/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;}

webbench.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 "socketTest.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 = 0; //修饰不同线程访问的变量int speed = 0;int failed = 0;int bytes = 0;/* globals *//* http协议版本号 */int http10 = 1; /* 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; //指定http方法int client = 1;          //并发数int force = 0;           //是否等待服务器应答,默认不应答int force_reload = 0;    //int proxyport = 80;      //代理服务器端口号,默认80char *proxyhost = NULL;  //代理服务器地址int benchtime = 30;      //运行时间,默认30s,可以用-t指定/* internal */int mypipes[2];char host[MAXHOSTNAMELEN];#define REQUEST_SIZE 2048char request[REQUEST_SIZE];/*struct option{  const char* name;    //参数名称  int         has_arg; //指明是否带数值,0-不带参数 1-必须带参数 2-可选参数  int        *flag;    //当flag为空时,直接将val的值从getopt_long的返回值返回出去,当非空时,val被赋值到flag指向的整型数中,而函数返回0  int         val;     //用于指定函数找到时的返回值};        //getopt_long第三个参数,option结构体数组*/static const struct option long_options[]={//参数名 |是否带参数 |返回方式 |返回值  {"force",no_argument,&force,1},  //force, 0, force, 1  {"reloac",no_argument,&force_reload,1},  {"time",required_argument,NULL,'t'}.//time, 1, NULL, 't'  {"help",no_argument,NULL,'?'},  {"http09",no_argument,NULL,'9'},  {"http10",no_argument,NULL,'1'},  {"http11",no_argument,NULL,'2'},  {"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'},//proxy, 2, NULL, 'p'  {"clients",required_argument,NULL,'c'},  {NULL,0,NULL,0}  //没传入第三个参数的情况};/* prototypes */static void build_request(const char *url);static int bench(void);static void benchcore(const char* host,const int port, const char *requeste);static void alarm_handler(int signal){timerexpired = 1;}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 = 0;int options_index = 0;char *tmp = NULL;if(1 == argc){usage();return 2;   //2 - bad param}/*--getopt_long函数:int getopt_long(int argc,char* const argv[], //argc,argv    -main  const char *optstring,//命令行传入的参数,有:表示可以可以指定值  const struct option *longopts,//指向一个由option结构体组成的数组   int *longindex);//如果非空,指向的变量记录当前找到的参数符合longopts里对应的下标值*/while((opt=getopt_long(argc, argv, "912Vfrt:p:c:?h", long_options, &options_index))!=EOF){  switch(opt)  {case  0 :                              break;case 'f': force = 1;                   break;case 'r': force_reload = 1;            break;case '9': http10 = 0;                  break;case '1': http10 = 1;                  break;case '2': http10 = 1;                  break;case 'V': printf(PROGRAM_VERSION"\n"); exit(0);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 2;}if(tmp == optarg + strlen(optarg) - 1){fprintf(stderr, "Error in options --proxy %s: Port number is missing.\n",optarg);return 2;}*tmp = '\0';proxyport = atoi(tmp + 1);   break;case ':':case 'h':case '?': usage(); return 2;           break;case 'c': clients = atoi(optarg);      break;  }}if(optind == argc) {//如果下一个参数的下标和参数个数相同fprintf(stderr, "webbench: Missing URL!\n");usage();return 2;}if(clients == 0) clients = 1;if(benchtime == 0) benchtime = 60;/*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("\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 0: printf(" (using HTTP/0.9)");break;case 2: printf(" (using HTTP/1.0)");break;}printf("\n");if(clients==1) printf("1 client");elseprintf("%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:url地址   创建好的请求放在全局变量request中====================== */void build_request(const char *url){char tmp[10];int  i;//请求地址和请求连接清0bzero(host, MAXHOSTNAMELEN);  //初始化host,置为0bzero(request, REQUEST_SIZE); //初始化requeste,置为0if(force_reload && proxyport!=NULL && http10<1) http10=1;if(method==METHOD_HEAD && http10<1) http10=1;if(method==METHOD_OPTIONS && http10<2) http10=2;if(method==METHOD_TRACE && http10<2) http10=2;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," ");           //拼接字符if(NULL == strstr(url,"://"))  //查找子串{fprintf(stderr, "\n%s: is not a valid URL.\n", url);exit(2);}if(strlen(url) > 1500){fprintf(stderr,"URL is too long.\n");exit(2);}if(proxyhost == NULL)          //代理是否为空if(0 != strncasecmp("http://",url,7)) //比较前7个字符串,相同返回0{fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n");exit(2);}/* protocol/host delimiter */i = strstr(url,"://")-url+3;if(strchr(url+i,'/') == NULL){fprintf(stderr,"\nInvalid URL syntax -hostname don't ends with '/'.\n");exit(2);}if(proxyhost == NULL){/* get port from hostname */if(index(url+i,':')!=NULL &&   index(url+i,':')<index(url+i,'/')) //判断是否给出端口号{// 将://到下一个:间字符复制给hoststrncpy(host, url+i, strchr(url+i,':')-url-i);//取出主机地址bzero(tmp, 10);strncpy(tmp, index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1);   //tmp暂存端口号proxyport = atoi(tmp);  //端口号转换为intif(proxyport == 0) proxyport = 80;} else {strncpy(host, url+i, strcspn(url+i,"/"));}strcat(request+strlen(request), url+i+strcspn(utl+i,"/"));}else{strcat(request,url);}if(http10 == 1)strcat(request," HTTP/1.0");else if(http10 == 2)strcat(request," HTTP/1.1");strcat(request,"\r\n");if(http10>0)strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\t\n");if(proxyhost==NULL && http10>0){strcat(request,"Host: ");strcat(request, host);strcat(request, "\r\n");}if(force_reload && proxyhost!=NULL){strcat(request, "Pragma: no-cache\r\n");}if(http10>1)strcat(request,"Connection: close\r\n");if(http10>0) strcat(request, "\r\n");}/* vraci system rc error kod *//*=================  创建管道和子进程,对http请求进行测试 ================== */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);/* 建立连接失败 */if(i < 0){fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");return 1;}close(i); //关闭socket/* 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){pid = fork();if(pid <= (pid_t) 0){/* child process or error */sleep(1); //make childs fasterbreak;}}if( pid < (pid_t) 0){fprintf(stderr, "problems forking worker no. %d\n", i);perror("fork failed.")return 3;}if(pid == (pid_t) 0){/* I am a child */if(proxyhost == NULL)benchcore(host,proxyport, request);elsebenchcore(proxyhost, proxyport, request);/* write results to pipe*/f = fdopen(mypipe[1], "w");if(f == NULL){perror("open pipe for writing failed.");return 3;}fprintf(f, "%d %d %d\n", speed, failed, bytes);fclose(f);return 0;}else{f = fdopen(mypipe[0], "r");if(f == NULL){perror("open pipe for reading failed.");return 3;}setvbuf(f, NULL, _IONBF, 0); //setvbufspeed = 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;failed += j;bytes  += k;if(--clients == 0) 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[1500];int s,i;struct sigaction sa;/*=========sigaction============int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);struct sigaction{void (*)int sa_handle;sigset_t    sa_mask;int         sa_flags;};  ==============================*//* setup alarm signal handler */sa.sa_handle = alarm_handler;sa.sa_flags = 0;if(sigaction(SIGALRM, &sa, NULL))exit 3;alarm(benchtime);rlen = strlen(req);nexttry:while(1){if(timerexpired){if(failed > 0){failed--;}return;}s = Socket(host, port);if(s < 0) { failed++; continue; }if(rlen != write(s, req, rlen)) { failed++; close(s); continue;}if(http10 == 0)if(shutdown(s, 1)) { failed++; close(s); continue; }if(force == 0){while(1){if(timerexpired) break;i = results(s, buf, 1500);if(i < 0){failed++;close(s);goto nexttry;}else {if( i==0 ) break;else bytes += i;}}}if(close(s)) {failed++; continue;}speed++;}}



0 0
原创粉丝点击