webbench源码解析
生活随笔
收集整理的這篇文章主要介紹了
webbench源码解析
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
webbench源碼解析
webbench簡介
webbench是一款用C編寫的開源工具,主要用來在Linux下進行網(wǎng)站壓力測試。最多可以模擬3萬個連接去測試網(wǎng)站的負載能力,并可以設(shè)置運行的客戶端數(shù)、測試時間、使用的http協(xié)議版本、請求方法、是否需要等待服務(wù)器響應(yīng)等選項,最后統(tǒng)計每分鐘相應(yīng)請求次數(shù)(paga/min)和每秒鐘傳輸數(shù)據(jù)量(byte/sec),以及請求成功數(shù)和失敗數(shù),表現(xiàn)測試網(wǎng)站的壓力承載能力。
代碼地址
代碼地址
版本
最新版webbench 1.5
運行方式
在目錄下,直接輸入make進行編譯,然后輸入
./webbench -c 3000 -t 5 url-c 3000表示模擬的客戶端連接數(shù)為3000,-t 5表示運行測試時間為5s,url是測試網(wǎng)站,即可進行測試。
工作流程
源碼解析
webbench的源碼由socket.c和webbench.c兩個文件組成,socket.c中只有一個方法int Socket,用來建立與目標的TCP連接,并返回客戶端連接使用的套接字,對命令行參數(shù)的處理,構(gòu)建請求,創(chuàng)建子進程進行壓力測試等在webbench.c文件中完成。
socket.c:
#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>/* * 建立與目標的TCP連接,返回客戶端連接使用的套接字* host: 目標域名或主機名* clientPort: 目標端口*/ int Socket(const char *host, int clientPort) {int sock; // 客戶端套接字標識符unsigned long inaddr; // 主機名的IP地址的數(shù)字形式struct sockaddr_in ad; // 套接字地址結(jié)構(gòu)struct hostent *hp; // 域名IP地址// 初始化目標套接字的地址,指定使用的IP協(xié)議為IPv4memset(&ad, 0, sizeof(ad));ad.sin_family = AF_INET;// 將目標主機名的IP地址轉(zhuǎn)換為數(shù)字inaddr = inet_addr(host);// 如果返回值不為INADDR_NONE,說明不是無效的IP地址,設(shè)置目標套接字的IP地址if (inaddr != INADDR_NONE)memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));// 否則說明是無效的IP地址,host不是主機名而是域名else{// 通過域名獲取IP地址hp = gethostbyname(host);// 如果獲取失敗。返回-1if (hp == NULL)return -1;// 設(shè)置目標套接字的IP地址memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);}// 設(shè)置目標套接字的端口號ad.sin_port = htons(clientPort);// 創(chuàng)建一個使用TCP協(xié)議的socketsock = socket(AF_INET, SOCK_STREAM, 0);// 如果創(chuàng)建失敗,直接返回if (sock < 0)return sock;// 進行連接,如果連接不成功,返回-1if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0)return -1;// 如果連接成功,返回sockreturn sock; }webbench.c:
#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=0; // 表示計時器是否到期,到期為1,否則為0 int speed=0; // 傳送速率(先獲得測試成功次數(shù),后面除以時間得到真正的傳輸速率) int failed=0; // 測試的失敗數(shù) int bytes=0; // 總共傳送的字節(jié)數(shù) /* globals */ // 使用的http協(xié)議版本,http/0.9為0,http/1.0為1,http/1.1為2 int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */ /* Allow: GET, HEAD, OPTIONS, TRACE */ #define METHOD_GET 0 // 方法GET的宏定義為0 #define METHOD_HEAD 1 // 方法HEAD的宏定義為1 #define METHOD_OPTIONS 2 // 方法OPTIONS的宏定義為2 #define METHOD_TRACE 3 // 方法TRACE的宏定義為3 #define PROGRAM_VERSION "1.5" // 程序的版本為1.5,即webbench1.5 int method=METHOD_GET; // 請求方式默認為GEI int clients=1; // 客戶端數(shù)量默認為2 int force=0; // 是否不等待服務(wù)器響應(yīng),發(fā)送請求后直接關(guān)閉連接,默認需要等待 int force_reload=0; // 是否強制代理服務(wù)器重新發(fā)送請求,默認不發(fā)送 int proxyport=80; // 訪問端口默認為80 char *proxyhost=NULL; // 代理服務(wù)器,默認無 int benchtime=30; // 測試運行時間默認為30s /* internal */ int mypipe[2]; // 讀寫管道,0為讀取端,1為寫入端 char host[MAXHOSTNAMELEN]; // 目標服務(wù)器的網(wǎng)絡(luò)地址 #define REQUEST_SIZE 2048 // 請求的最大長度 char request[REQUEST_SIZE]; // 請求內(nèi)容// 構(gòu)造長選項與短選項的對應(yīng)關(guān)系,no_argument表示選項沒有參數(shù),required_argument表示選項需要參數(shù) 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} };/* prototypes */ static void benchcore(const char* host,const int port, const char *request); static int bench(void); static void build_request(const char *url);// 信號處理函數(shù) static void alarm_handler(int signal) {// 設(shè)置計時器到期timerexpired=1; } // 用法,描述了參數(shù)設(shè)置,可打印出來 static void usage(void) {fprintf(stderr,// 用法是webbench后面加相應(yīng)的選項,最后加上要測試的URL"webbench [option]... URL\n"// 不用等待服務(wù)器的響應(yīng),發(fā)送請求后直接關(guān)閉連接" -f|--force Don't wait for reply from server.\n"// 發(fā)送重新加載請求(無緩存)" -r|--reload Send reload request - Pragma: no-cache.\n"// 運行基準測試的秒數(shù),默認為30s" -t|--time <sec> Run benchmark for <sec> seconds. Default 30.\n"// 使用代理服務(wù)器發(fā)送請求" -p|--proxy <server:port> Use proxy server for request.\n"// 一次運行的http客戶端個數(shù),默認為1" -c|--clients <n> Run <n> HTTP clients at once. Default one.\n"// 使用HTTP/0.9協(xié)議" -9|--http09 Use HTTP/0.9 style requests.\n"// 使用HTTP/1.0協(xié)議" -1|--http10 Use HTTP/1.0 protocol.\n"// 使用HTTP/1.1協(xié)議" -2|--http11 Use HTTP/1.1 protocol.\n"// 請求方法使用GET" --get Use GET request method.\n"// 請求方法使用HEAD" --head Use HEAD request method.\n"// 請求方法使用OPTIONS" --options Use OPTIONS request method.\n"// 請求方法使用TRACE" --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;// 如果在終端只輸入了./webbench,后面沒有跟參數(shù),打印用法,直接退出程序,返回碼為2,表示格式錯誤if(argc==1){usage();return 2;} // 循環(huán)解析終端輸入選項,每次解析一個選項及其后面可能跟的參數(shù)while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF ){switch(opt){case 0 : break;// 如果選項為'f',那么設(shè)置不等待服務(wù)器響應(yīng),發(fā)送請求后直接關(guān)閉連接case 'f': force=1;break;// 如果選項為'r',那么設(shè)置強制代理服務(wù)器重新發(fā)送請求case 'r': force_reload=1;break; // 如果選項為'9',那么設(shè)置在條件允許范圍內(nèi)使用HTTP/0.9協(xié)議case '9': http10=0;break;// 如果選項為'1',那么設(shè)置在條件允許范圍內(nèi)使用HTTP/1.0協(xié)議case '1': http10=1;break;// 如果選項為'2',那么設(shè)置在條件允許范圍內(nèi)使用HTTP/1.1協(xié)議case '2': http10=2;break;// 如果選項為'V',那么打印程序版本,然后退出程序case 'V': printf(PROGRAM_VERSION"\n");exit(0);// 如果選項為't',那么記錄其后所跟參數(shù)數(shù)值到運行基準時間benchtime中case 't': benchtime=atoi(optarg);break;// 如果選項為'p',那么表示使用代理服務(wù)器 case 'p': /* proxy server parsing server:port */// 記錄參數(shù)中最后出現(xiàn)字符':'的位置及其之后的內(nèi)容到tmp中tmp=strrchr(optarg,':');// 記錄參數(shù)到代理主機proxyhost中proxyhost=optarg;// 如果參數(shù)中沒有字符':',說明沒有端口號,直接退出switchif(tmp==NULL){break;}// 如果參數(shù)中只有一個字符':',說明端口號在最前,打印缺失主機名,然后直接返回,返回碼為2,表示格式錯誤if(tmp==optarg){fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg);return 2;}// 如果參數(shù)中最后一個':'之后沒有內(nèi)容,打印缺失端口號,然后直接返回,返回碼為2,表示格式錯誤if(tmp==optarg+strlen(optarg)-1){fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg);return 2;}// 將proxyhost中的內(nèi)容從最后一個':'處進行截斷,只記錄':'之前的內(nèi)容*tmp='\0';// 將最后一個':'之后內(nèi)容轉(zhuǎn)化為數(shù)字并記錄在代理服務(wù)器端口號proxyport中proxyport=atoi(tmp+1);break;// 如果選項為':'、'h'、'?',那么打印用法,并直接退出程序,返回碼為2,表示格式錯誤case ':':case 'h':case '?': usage();return 2;break;// 如果選項為'c',那么記錄其后所跟參數(shù)數(shù)值到客戶端數(shù)量clients中case 'c': clients=atoi(optarg);break;}}// 如果參數(shù)后沒有其它內(nèi)容,打印缺失測試URL,打印用法后直接退出程序,返回碼為2,表示格式錯誤if(optind==argc) {fprintf(stderr,"webbench: Missing URL!\n");usage();return 2;}// 如果輸入客戶端數(shù)量為0,則設(shè)置為默認值1if(clients==0) clients=1;// 如果輸入運行測試的秒數(shù)為0,則設(shè)置為默認值60if(benchtime==0) benchtime=60;/* Copyright */// 打印版權(quán)信息fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n""Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n");// 將測試URL作為參數(shù)傳入build_request方法中,構(gòu)建http請求build_request(argv[optind]);/* print bench info */// 打印Benchmarking、請求方法、測試URLprintf("\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]);// 判斷使用的http協(xié)議類型,如果使用的是默認的HTTP/1.0則不打印switch(http10){// 如果http10的值為0,打印使用HTTP/0.9case 0: printf(" (using HTTP/0.9)");break;// 如果http10的值為2,打印使用HTTP/1.1case 2: printf(" (using HTTP/1.1)");break;}printf("\n");// 打印客戶端數(shù)、運行秒數(shù)if(clients==1) printf("1 client");elseprintf("%d clients",clients);printf(", running %d sec", benchtime);// 打印是否不等待響應(yīng)就提前關(guān)閉連接、是否通過代理服務(wù)器發(fā)送請求,是否無緩存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參數(shù),構(gòu)建對測試url的http請求 void build_request(const char *url) {char tmp[10];int i;bzero(host,MAXHOSTNAMELEN);bzero(request,REQUEST_SIZE);// 緩存和代理需要HTTP/1.0及以上才能使用,自動調(diào)整使用http協(xié)議版本if(force_reload && proxyhost!=NULL && http10<1) http10=1;// 請求方法HEAD需要HTTP/1.0及以上才能使用,自動調(diào)整使用http協(xié)議版本if(method==METHOD_HEAD && http10<1) http10=1;// 請求方法OPTIONS和TRACE需要HTTP/1.1及以上才能使用,自動調(diào)整使用http協(xié)議版本if(method==METHOD_OPTIONS && http10<2) http10=2;if(method==METHOD_TRACE && http10<2) http10=2;// 根據(jù)請求方法填充請求報文的請求行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," ");/* 判斷URL的格式合法性 */// 如果url中沒有"://",打印是無效的URL,直接退出程序,返回碼為2,表示格式錯誤if(NULL==strstr(url,"://")){fprintf(stderr, "\n%s: is not a valid URL.\n",url);exit(2);}// 如果url的長度大于1500,打印URL過長,直接退出程序,返回碼為2,表示格式錯誤if(strlen(url)>1500){fprintf(stderr,"URL is too long.\n");exit(2);}// 如果不使用代理服務(wù)器if(proxyhost==NULL)// 如果url的前7位不是任意大小寫的"http://",打印僅直接支持HTTP協(xié)議,可能需要選擇使用代理服務(wù)器的選項,直接退出程序,返回碼為2,表示格式錯誤if (0!=strncasecmp("http://",url,7)) { fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n");exit(2);}/* protocol/host delimiter */// 定位目標主機名的開始位置i=strstr(url,"://")-url+3;/* printf("%d\n",i); */// 如果主機名后沒有'/',說明主機名沒有以'/'結(jié)尾,打印是無效的URL,直接退出程序if(strchr(url+i,'/')==NULL) {fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n");exit(2);}/* 判斷完url的合法性后填寫url到請求行 */// 沒有設(shè)置代理服務(wù)器時if(proxyhost==NULL){/* get port from hostname */// 從主機名之后開始尋找':'所在的位置,如果':'存在且位置在'/'之前if(index(url+i,':')!=NULL &&index(url+i,':')<index(url+i,'/')){// 將找到的':'之前的內(nèi)容,即去掉端口號,復(fù)制進目標服務(wù)器地址host中strncpy(host,url+i,strchr(url+i,':')-url-i);bzero(tmp,10);// 將':'之后的內(nèi)容,即端口號,復(fù)制進tmp中,并轉(zhuǎn)換為數(shù)字存進proxyport中strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1);/* printf("tmp=%s\n",tmp); */proxyport=atoi(tmp);// 如果proxyport值為0,有可能寫了':'但沒寫端口號,那么設(shè)置為默認端口號80if(proxyport==0) proxyport=80;} else // 如果沒找到':',說明沒有端口號{// 將主機名之后,"/"之前的內(nèi)容復(fù)制進host中strncpy(host,url+i,strcspn(url+i,"/"));}// printf("Host=%s\n",host);// 將主機名之后找到的"/"之后的內(nèi)容拼接到請求行的相應(yīng)位置strcat(request+strlen(request),url+i+strcspn(url+i,"/"));} else{// printf("ProxyHost=%s\nProxyPort=%d\n",proxyhost,proxyport);// 設(shè)置了代理服務(wù)器時就直接將url拼接進請求行中strcat(request,url);}// 將http協(xié)議版本及其之后的"\r\n"拼接到請求行中if(http10==1)strcat(request," HTTP/1.0");else if (http10==2)strcat(request," HTTP/1.1");strcat(request,"\r\n");/* 填寫請求頭 */// 如果使用的是HTTP/1.0及其之后的版本,拼接用戶代理到請求頭中if(http10>0)strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n");// 如果沒有使用代理服務(wù)器且使用的是HTTP/1.0及其之后的版本,拼接目標服務(wù)器地址到請求頭中if(proxyhost==NULL && http10>0){strcat(request,"Host: ");strcat(request,host);strcat(request,"\r\n");}// 如果設(shè)置了強制代理服務(wù)器重新發(fā)送請求且代理服務(wù)器不為空,拼接不使用緩存到請求頭中if(force_reload && proxyhost!=NULL){strcat(request,"Pragma: no-cache\r\n");}// 如果使用的是HTTP/1.1協(xié)議,因為不用傳輸任何內(nèi)容,那么拼接不使用長連接到請求頭中,這樣可以降低維護連接的消耗if(http10>1)strcat(request,"Connection: close\r\n");/* add empty line at end */// 最后填入空行完成構(gòu)建請求頭if(http10>0) strcat(request,"\r\n"); // printf("Req=%s\n",request); }/* vraci system rc error kod */ // 壓力測試方法,創(chuàng)建指定個數(shù)子進程客戶端,不斷對目標服務(wù)器或代理服務(wù)器發(fā)起連接請求,并統(tǒng)計相應(yīng)數(shù)據(jù) static int bench(void) {int i,j,k; pid_t pid=0;FILE *f;/* check avaibility of target server */// 建立一個TCP連接,檢查連接可用性,如果設(shè)置了代理服務(wù)器,那么連接代理服務(wù)器,否則直接連接目標服務(wù)器i=Socket(proxyhost==NULL?host:proxyhost,proxyport);// 連接失敗那么打印錯誤信息,并直接退出,返回碼為1,表示基準測試失敗(服務(wù)器未聯(lián)機)if(i<0) { fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");return 1;}// 關(guān)閉連接,這次連接不計入測試close(i);/* create pipe */// 創(chuàng)建管道,如果失敗,直接退出程序,返回碼為3,表示內(nè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();*//* fork childs */// 創(chuàng)建clients個子進程,由子進程進行真正的測試for(i=0;i<clients;i++){pid=fork();// 如果是子進程或者創(chuàng)建失敗,休眠1s后退出循環(huán),讓父進程先執(zhí)行,完成初始化,并且保證子進程中不會再fork出新的子進程if(pid <= (pid_t) 0){/* child process or error*/sleep(1); /* make childs faster */break;}}// 如果創(chuàng)建子進程失敗,那么打印fork失敗,直接退出程序,返回碼為3,表示fork失敗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 */// 如果不使用代理服務(wù)器,那么子進程直接對目標服務(wù)器發(fā)出http請求,否則向代理服務(wù)器發(fā)出http請求if(proxyhost==NULL)benchcore(host,proxyport,request);elsebenchcore(proxyhost,proxyport,request);/* write results to pipe */// 獲取管道寫端的文件指針f=fdopen(mypipe[1],"w");// 獲取失敗,直接退出,返回碼為3,表示內(nèi)部錯誤if(f==NULL){perror("open pipe for writing failed.");return 3;}/* fprintf(stderr,"Child - %d %d\n",speed,failed); */// 將子進程的傳輸速率,測試失敗數(shù),總傳輸字節(jié)數(shù)寫入管道,關(guān)閉寫端fprintf(f,"%d %d %d\n",speed,failed,bytes);fclose(f);// 返回0,表示運行成功return 0;} else // 父進程中{// 獲取管道讀端的指針f=fdopen(mypipe[0],"r");// 獲取失敗,直接退出,返回碼為3,表示內(nèi)部錯誤if(f==NULL) {perror("open pipe for reading failed.");return 3;}// 設(shè)置不使用緩沖。每個I/O操作都被即時寫入管道setvbuf(f,NULL,_IONBF,0);// 初始化傳輸速率,測試失敗次數(shù),傳輸總字節(jié)數(shù)都為0speed=0;failed=0;bytes=0;// 父進程循環(huán)讀取數(shù)據(jù) while(1){// 循環(huán)從管道中每3個一組讀取子進程的輸出數(shù)據(jù),并且獲取成功讀取的參數(shù)個數(shù)pid=fscanf(f,"%d %d %d",&i,&j,&k);// 如果成功讀取的個數(shù)小于2,說明有子進程中途掛掉,直接退出讀取循環(huán)if(pid<2){fprintf(stderr,"Some of our childrens died.\n");break;}// 否則更新傳輸速率(測試成功個數(shù)),測試失敗次數(shù),傳輸總字節(jié)數(shù)speed+=i;failed+=j;bytes+=k;/* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); */// 客戶端數(shù)減一后如果等于0,說明沒有多的客戶端數(shù)據(jù)讀取,直接退出循環(huán)if(--clients==0) break;}// 關(guān)閉讀端fclose(f);// 打印統(tǒng)計的總的測試傳輸速度,請求成功數(shù)與失敗數(shù)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; }// 子進程在測試時間內(nèi)不斷向服務(wù)器建立連接并發(fā)送http請求,計時器到期后退出子線程,統(tǒng)計相應(yīng)數(shù)據(jù) 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 */// 設(shè)置SIGALRM的信號處理函數(shù)sa.sa_handler=alarm_handler;sa.sa_flags=0;if(sigaction(SIGALRM,&sa,NULL))exit(3);// 設(shè)置計時器時間為運行測試的時間,到期后發(fā)送SIGALRM信號alarm(benchtime);// 獲取請求報文大小rlen=strlen(req);// 進入循環(huán),每次客戶端建立一個連接,計時器時間到期后再退出nexttry:while(1){// 如果timerexpired等于1,說明收到了SIGALRM信號,表示計時器到期了,直接返回if(timerexpired){// 如果失敗的測試數(shù)大于0,那么失敗的測試數(shù)減一if(failed>0){/* fprintf(stderr,"Correcting failed by signal\n"); */failed--;}return;}// 建立與目標服務(wù)器的TCP連接s=Socket(host,port);// 如果連接失敗,測試的失敗數(shù)加一,繼續(xù)循環(huán) if(s<0) { failed++;continue;} // 如果請求報文寫入套接字失敗,測試的失敗數(shù)加一,繼續(xù)循環(huán)if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;}// 如果使用HTTP/0.9協(xié)議,因為會在服務(wù)器回復(fù)后自動斷開連接,所以可以先關(guān)閉寫端if(http10==0) // 如果寫端關(guān)閉失敗,那么說明是不正常的連接狀態(tài),測試的失敗數(shù)加一,關(guān)閉連接,繼續(xù)循環(huán)if(shutdown(s,1)) { failed++;close(s);continue;}// 如果設(shè)置需要等待服務(wù)器響應(yīng),那么還要處理響應(yīng)數(shù)據(jù),否則直接關(guān)閉連接if(force==0) {/* read all available data from socket */// 從套接字中讀取數(shù)據(jù)while(1){// 如果計時器到期,結(jié)束讀取if(timerexpired) break; // 將數(shù)據(jù)讀取進buf中i=read(s,buf,1500);/* fprintf(stderr,"%d\n",i); */// 如果讀取失敗,測試的失敗數(shù)加一,關(guān)閉連接,繼續(xù)循環(huán),客戶端重新建立連接,直到計時器到期后再退出if(i<0) { failed++;close(s);goto nexttry;}else// 如果已經(jīng)讀取到文件末尾,結(jié)束讀取數(shù)據(jù)if(i==0) break;// 如果讀取到了數(shù)據(jù),將總共傳送的字節(jié)數(shù)加上讀取到的數(shù)據(jù)的字節(jié)數(shù)elsebytes+=i;}}// 關(guān)閉連接,如果失敗,測試失敗數(shù)加一,繼續(xù)循環(huán)if(close(s)) {failed++;continue;}// 傳輸速率(這里用測試成功數(shù)表示,后面除以時間得到真正的傳輸速率)加一speed++;} }總結(jié)
以上是生活随笔為你收集整理的webbench源码解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用Python实现一个简单的智能换脸软件
- 下一篇: windows7 64位环境下安装apa