天天看點

webbench網絡壓力測試源碼

今天中午閑來無事花了5分鐘時間看了遍webbench網絡壓力測試的源代碼,索性将其漢化,英語水準有限,敬請批評指正。

1、适用系統:Linux

2、編譯安裝:

tar zxvf webbench-1.5.tar.gz

cd webbench-1.5

make && make install

3、使用:

webbench -c 500 -t 30 http://127.0.0.1/test.jpg

  參數說明:-c表示并發數,-t表示時間(秒)

測試結果示例:

Webbench - Simple Web Benchmark 1.5

Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://127.0.0.1/test.jpg

500 clients, running 30 sec.

Speed=3230 pages/min, 11614212 bytes/sec.

Requests: 1615 susceed, 0 failed

漢化主要是對webbench.c檔案的漢化

/*

 * (C) Radim Kolar 1997-2004

 * 這是一個免費的開源軟體, 具體細節請檢視GNU公開第2版

 * 的許可.

 *

 * 簡單的網際網路伺服器測試基準程式:

 * 使用方法:

 *   webbench --help

 * 傳回代碼:

 *    0 - 正确

 *    1 - 伺服器不線上

 *    2 - 錯誤的參數

 *    3 - 網絡錯誤程式錯誤

 *

 */

#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>

/* 變量 */

volatile int timerexpired=0;

int speed=0;

int failed=0;

int bytes=0;

/* 全局變量 */

int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */

/* 定義: 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=1;

int force=0;

int force_reload=0;

int proxyport=80;

char *proxyhost=NULL;

int benchtime=30;

/* 網絡相關變量 */

int mypipe[2];

char host[MAXHOSTNAMELEN];

#define REQUEST_SIZE 2048

char request[REQUEST_SIZE];

static const struct option long_options[]=

{

 {"force",no_argument,&force,1},

 {"reload",no_argument,&force_reload,1},

 {"time",required_argument,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'},

 {"clients",required_argument,NULL,'c'},

 {NULL,0,NULL,0}

};

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=1;

static void usage(void)

   fprintf(stderr,

 "webbench [option]... URL\n"

 "  -f|--force               不需要等待主機的回應強制執行.\n"

 "  -r|--reload              發送無緩存的重載請求.\n"

 "  -t|--time <sec>          使用本程式時間間隔預設是30秒.\n"

 "  -p|--proxy <server:port> 使用代理網關發送請求.\n"

 "  -c|--clients <n>         使用并發數.\n"

 "  -9|--http09              使用 HTTP/0.9 類型發送請求.\n"

 "  -1|--http10              使用 HTTP/1.0 協定.\n"

 "  -2|--http11              使用 HTTP/1.1 協定.\n"

 "  --get                    使用 GET 請求方式.\n"

 "  --head                   使用 HEAD 請求方式.\n"

 "  --options                使用 OPTIONS 請求方式.\n"

 "  --trace                  使用 TRACE 請求方式.\n"

 "  -?|-h|--help             幫助資訊.\n"

 "  -V|--version             顯示程式版本号.\n"

 );

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

 int opt=0;

 int options_index=0;

 char *tmp=NULL;

 if(argc==1)

 {

   usage();

          return 2;

 }

 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=2;break;

   case 'V': printf(PROGRAM_VERSION"\n");exit(0);

   case 't': benchtime=atoi(optarg);break;     

   case 'p':

      /* 網絡解析端口 */

      tmp=strrchr(optarg,':');

      proxyhost=optarg;

      if(tmp==NULL)

      {

       break;

      }

      if(tmp==optarg)

       fprintf(stderr,"Error in option --proxy %s: 主機錯誤無法找到主機.\n",optarg);

       return 2;

      if(tmp==optarg+strlen(optarg)-1)

       fprintf(stderr,"Error in option --proxy %s 端口錯誤無法打開端口.\n",optarg);

      *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: 連接配接位址錯誤!\n");

        usage();

        return 2;

                    }

 if(clients==0) clients=1;

 if(benchtime==0) benchtime=60;

 /* 版權 */

 fprintf(stderr,"Webbench - 簡單的網際網路伺服器測試基準程式 "PROGRAM_VERSION"\n"

  "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n"

  );

 build_request(argv[optind]);

 /* 列印傳回值 */

 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(" (使用 HTTP/0.9)");break;

  case 2: printf(" (使用 HTTP/1.1)");break;

 printf("\n");

 if(clients==1) printf("1 client");

 else

   printf("%d clients",clients);

 printf(", running %d sec", benchtime);

 if(force) printf(", early socket close");

 if(proxyhost!=NULL) printf(", via 代理伺服器 %s:%d",proxyhost,proxyport);

 if(force_reload) printf(", forcing reload");

 printf(".\n");

 return bench();

}

void build_request(const char *url)

  char tmp[10];

  int i;

  bzero(host,MAXHOSTNAMELEN);

  bzero(request,REQUEST_SIZE);

  if(force_reload && proxyhost!=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))

    { fprintf(stderr,"\n僅支援http協定, 請設定其他的網關.\n");

             exit(2);

           }

  /* 主機協定 */

  i=strstr(url,"://")-url+3;

  /* printf("%d\n",i); */

  if(strchr(url+i,'/')==NULL) {

                                fprintf(stderr,"\n無效的Url文法 - 主機名結束沒有加 '/'.\n");

                                exit(2);

                              }

   /* 獲得主機端口 */

   if(index(url+i,':')!=NULL &&

      index(url+i,':')<index(url+i,'/'))

   {

    strncpy(host,url+i,strchr(url+i,':')-url-i);

    bzero(tmp,10);

    strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1);

    /* printf("tmp=%s\n",tmp); */

    proxyport=atoi(tmp);

    if(proxyport==0) proxyport=80;

   } 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==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"\r\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");

  // printf("Req=%s\n",request);

/* 程式資源錯誤處理 */

static int bench(void)

  int i,j,k; 

  pid_t pid=0;

  FILE *f;

  /* 建立一個目标伺服器的套接字 */

  i=Socket(proxyhost==NULL?host:proxyhost,proxyport);

  if(i<0) {

    fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");

           return 1;

         }

  close(i);

  /* 建立一個管道 */

  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();

  */

  /* 建立子程序 */

  for(i=0;i<clients;i++)

    pid=fork();

    if(pid <= (pid_t) 0)

    {

     /* 子程序如果出現錯誤将退出*/

            sleep(1); /* 将程序進入休眠狀态 */

     break;

    }

  if( pid< (pid_t) 0)

          fprintf(stderr,"problems forking worker no. %d\n",i);

   perror("fork failed.");

  if(pid== (pid_t) 0)

    /* 建立子程序成功 */

    if(proxyhost==NULL)

      benchcore(host,proxyport,request);

         else

      benchcore(proxyhost,proxyport,request);

         /* 向管道中寫入内容 */

  f=fdopen(mypipe[1],"w");

  if(f==NULL)

   perror("open pipe for writing failed.");

  /* fprintf(stderr,"Child - %d %d\n",speed,failed); */

  fprintf(f,"%d %d %d\n",speed,failed,bytes);

  fclose(f);

  return 0;

   f=fdopen(mypipe[0],"r");

   if(f==NULL)

    perror("打開讀管道失敗.");

    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,"子程序死亡.\n");

                       break;

                  }

    speed+=i;

    failed+=j;

    bytes+=k;

    /* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); */

    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;

 /* 設定警告處理機制 */

 sa.sa_handler=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)

       {

          /* fprintf(stderr,"信号量錯誤\n"); */

          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=read(s,buf,1500);

              /* fprintf(stderr,"%d\n",i); */

       if(i<0)

              {

                 failed++;

                 close(s);

                 goto nexttry;

              }

        else

         if(i==0) break;

          bytes+=i;

     }

    if(close(s)) {failed++;continue;}

    speed++;

繼續閱讀