日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

webbench源码解析

發布時間:2024/6/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 webbench源码解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

webbench源碼解析

webbench簡介

webbench是一款用C編寫的開源工具,主要用來在Linux下進行網站壓力測試。最多可以模擬3萬個連接去測試網站的負載能力,并可以設置運行的客戶端數、測試時間、使用的http協議版本、請求方法、是否需要等待服務器響應等選項,最后統計每分鐘相應請求次數(paga/min)和每秒鐘傳輸數據量(byte/sec),以及請求成功數和失敗數,表現測試網站的壓力承載能力。

代碼地址

代碼地址

版本

最新版webbench 1.5

運行方式

在目錄下,直接輸入make進行編譯,然后輸入

./webbench -c 3000 -t 5 url

-c 3000表示模擬的客戶端連接數為3000,-t 5表示運行測試時間為5s,url是測試網站,即可進行測試。

工作流程

  • 首先在主函數中處理終端輸入的命令參數,然后利用build_request方法解析終端輸入的測試url,構造HTTP請求,打印相關信息后,使用bench方法開始壓力測試。
  • 在bench方法中,首先嘗試對目標建立TCP連接,檢查連接可用性,如果失敗,說明目標可能未聯機,直接退出程序,成功則繼續進行。
  • 創建管道,然后根據終端輸入客戶端個數,創建指定個數的子進程,在每個子進程中,使用benchcore方法在測試時間內不斷向服務器建立連接并發送http請求。
  • 在benchcore方法中,每個子進程會先根據終端輸入測試時間,設置計時器的時間,然后進入循環,每次循環客戶端都會向目標建立連接并發送HTTP請求,然后更新請求成功數和失敗數、傳輸數據量等信息,當計時器到期后,退出循環,子進程結束。
  • 每個子進程將最后總共的傳輸速率,測試失敗數,總傳輸字節數等相應統計信息寫入管道,父進程則負責從管道中循環讀取子進程的相應統計信息,進行統計,并將最終每分鐘相應請求次數(paga/min)和每秒鐘傳輸數據量(byte/sec),以及請求成功數和失敗數等壓力測試數據打印在屏幕上。
  • 源碼解析

    webbench的源碼由socket.c和webbench.c兩個文件組成,socket.c中只有一個方法int Socket,用來建立與目標的TCP連接,并返回客戶端連接使用的套接字,對命令行參數的處理,構建請求,創建子進程進行壓力測試等在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地址的數字形式struct sockaddr_in ad; // 套接字地址結構struct hostent *hp; // 域名IP地址// 初始化目標套接字的地址,指定使用的IP協議為IPv4memset(&ad, 0, sizeof(ad));ad.sin_family = AF_INET;// 將目標主機名的IP地址轉換為數字inaddr = inet_addr(host);// 如果返回值不為INADDR_NONE,說明不是無效的IP地址,設置目標套接字的IP地址if (inaddr != INADDR_NONE)memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));// 否則說明是無效的IP地址,host不是主機名而是域名else{// 通過域名獲取IP地址hp = gethostbyname(host);// 如果獲取失敗。返回-1if (hp == NULL)return -1;// 設置目標套接字的IP地址memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);}// 設置目標套接字的端口號ad.sin_port = htons(clientPort);// 創建一個使用TCP協議的socketsock = socket(AF_INET, SOCK_STREAM, 0);// 如果創建失敗,直接返回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; // 傳送速率(先獲得測試成功次數,后面除以時間得到真正的傳輸速率) int failed=0; // 測試的失敗數 int bytes=0; // 總共傳送的字節數 /* globals */ // 使用的http協議版本,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; // 客戶端數量默認為2 int force=0; // 是否不等待服務器響應,發送請求后直接關閉連接,默認需要等待 int force_reload=0; // 是否強制代理服務器重新發送請求,默認不發送 int proxyport=80; // 訪問端口默認為80 char *proxyhost=NULL; // 代理服務器,默認無 int benchtime=30; // 測試運行時間默認為30s /* internal */ int mypipe[2]; // 讀寫管道,0為讀取端,1為寫入端 char host[MAXHOSTNAMELEN]; // 目標服務器的網絡地址 #define REQUEST_SIZE 2048 // 請求的最大長度 char request[REQUEST_SIZE]; // 請求內容// 構造長選項與短選項的對應關系,no_argument表示選項沒有參數,required_argument表示選項需要參數 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);// 信號處理函數 static void alarm_handler(int signal) {// 設置計時器到期timerexpired=1; } // 用法,描述了參數設置,可打印出來 static void usage(void) {fprintf(stderr,// 用法是webbench后面加相應的選項,最后加上要測試的URL"webbench [option]... URL\n"// 不用等待服務器的響應,發送請求后直接關閉連接" -f|--force Don't wait for reply from server.\n"// 發送重新加載請求(無緩存)" -r|--reload Send reload request - Pragma: no-cache.\n"// 運行基準測試的秒數,默認為30s" -t|--time <sec> Run benchmark for <sec> seconds. Default 30.\n"// 使用代理服務器發送請求" -p|--proxy <server:port> Use proxy server for request.\n"// 一次運行的http客戶端個數,默認為1" -c|--clients <n> Run <n> HTTP clients at once. Default one.\n"// 使用HTTP/0.9協議" -9|--http09 Use HTTP/0.9 style requests.\n"// 使用HTTP/1.0協議" -1|--http10 Use HTTP/1.0 protocol.\n"// 使用HTTP/1.1協議" -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,后面沒有跟參數,打印用法,直接退出程序,返回碼為2,表示格式錯誤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;// 如果選項為'f',那么設置不等待服務器響應,發送請求后直接關閉連接case 'f': force=1;break;// 如果選項為'r',那么設置強制代理服務器重新發送請求case 'r': force_reload=1;break; // 如果選項為'9',那么設置在條件允許范圍內使用HTTP/0.9協議case '9': http10=0;break;// 如果選項為'1',那么設置在條件允許范圍內使用HTTP/1.0協議case '1': http10=1;break;// 如果選項為'2',那么設置在條件允許范圍內使用HTTP/1.1協議case '2': http10=2;break;// 如果選項為'V',那么打印程序版本,然后退出程序case 'V': printf(PROGRAM_VERSION"\n");exit(0);// 如果選項為't',那么記錄其后所跟參數數值到運行基準時間benchtime中case 't': benchtime=atoi(optarg);break;// 如果選項為'p',那么表示使用代理服務器 case 'p': /* proxy server parsing server:port */// 記錄參數中最后出現字符':'的位置及其之后的內容到tmp中tmp=strrchr(optarg,':');// 記錄參數到代理主機proxyhost中proxyhost=optarg;// 如果參數中沒有字符':',說明沒有端口號,直接退出switchif(tmp==NULL){break;}// 如果參數中只有一個字符':',說明端口號在最前,打印缺失主機名,然后直接返回,返回碼為2,表示格式錯誤if(tmp==optarg){fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg);return 2;}// 如果參數中最后一個':'之后沒有內容,打印缺失端口號,然后直接返回,返回碼為2,表示格式錯誤if(tmp==optarg+strlen(optarg)-1){fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg);return 2;}// 將proxyhost中的內容從最后一個':'處進行截斷,只記錄':'之前的內容*tmp='\0';// 將最后一個':'之后內容轉化為數字并記錄在代理服務器端口號proxyport中proxyport=atoi(tmp+1);break;// 如果選項為':'、'h'、'?',那么打印用法,并直接退出程序,返回碼為2,表示格式錯誤case ':':case 'h':case '?': usage();return 2;break;// 如果選項為'c',那么記錄其后所跟參數數值到客戶端數量clients中case 'c': clients=atoi(optarg);break;}}// 如果參數后沒有其它內容,打印缺失測試URL,打印用法后直接退出程序,返回碼為2,表示格式錯誤if(optind==argc) {fprintf(stderr,"webbench: Missing URL!\n");usage();return 2;}// 如果輸入客戶端數量為0,則設置為默認值1if(clients==0) clients=1;// 如果輸入運行測試的秒數為0,則設置為默認值60if(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");// 將測試URL作為參數傳入build_request方法中,構建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協議類型,如果使用的是默認的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");// 打印客戶端數、運行秒數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的http請求 void build_request(const char *url) {char tmp[10];int i;bzero(host,MAXHOSTNAMELEN);bzero(request,REQUEST_SIZE);// 緩存和代理需要HTTP/1.0及以上才能使用,自動調整使用http協議版本if(force_reload && proxyhost!=NULL && http10<1) http10=1;// 請求方法HEAD需要HTTP/1.0及以上才能使用,自動調整使用http協議版本if(method==METHOD_HEAD && http10<1) http10=1;// 請求方法OPTIONS和TRACE需要HTTP/1.1及以上才能使用,自動調整使用http協議版本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," ");/* 判斷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);}// 如果不使用代理服務器if(proxyhost==NULL)// 如果url的前7位不是任意大小寫的"http://",打印僅直接支持HTTP協議,可能需要選擇使用代理服務器的選項,直接退出程序,返回碼為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); */// 如果主機名后沒有'/',說明主機名沒有以'/'結尾,打印是無效的URL,直接退出程序if(strchr(url+i,'/')==NULL) {fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n");exit(2);}/* 判斷完url的合法性后填寫url到請求行 */// 沒有設置代理服務器時if(proxyhost==NULL){/* get port from hostname */// 從主機名之后開始尋找':'所在的位置,如果':'存在且位置在'/'之前if(index(url+i,':')!=NULL &&index(url+i,':')<index(url+i,'/')){// 將找到的':'之前的內容,即去掉端口號,復制進目標服務器地址host中strncpy(host,url+i,strchr(url+i,':')-url-i);bzero(tmp,10);// 將':'之后的內容,即端口號,復制進tmp中,并轉換為數字存進proxyport中strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1);/* printf("tmp=%s\n",tmp); */proxyport=atoi(tmp);// 如果proxyport值為0,有可能寫了':'但沒寫端口號,那么設置為默認端口號80if(proxyport==0) proxyport=80;} else // 如果沒找到':',說明沒有端口號{// 將主機名之后,"/"之前的內容復制進host中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);// 設置了代理服務器時就直接將url拼接進請求行中strcat(request,url);}// 將http協議版本及其之后的"\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");// 如果沒有使用代理服務器且使用的是HTTP/1.0及其之后的版本,拼接目標服務器地址到請求頭中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");}// 如果使用的是HTTP/1.1協議,因為不用傳輸任何內容,那么拼接不使用長連接到請求頭中,這樣可以降低維護連接的消耗if(http10>1)strcat(request,"Connection: close\r\n");/* add empty line at end */// 最后填入空行完成構建請求頭if(http10>0) 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=0;FILE *f;/* check avaibility of target server */// 建立一個TCP連接,檢查連接可用性,如果設置了代理服務器,那么連接代理服務器,否則直接連接目標服務器i=Socket(proxyhost==NULL?host:proxyhost,proxyport);// 連接失敗那么打印錯誤信息,并直接退出,返回碼為1,表示基準測試失敗(服務器未聯機)if(i<0) { fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");return 1;}// 關閉連接,這次連接不計入測試close(i);/* create pipe */// 創建管道,如果失敗,直接退出程序,返回碼為3,表示內部錯誤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 */// 創建clients個子進程,由子進程進行真正的測試for(i=0;i<clients;i++){pid=fork();// 如果是子進程或者創建失敗,休眠1s后退出循環,讓父進程先執行,完成初始化,并且保證子進程中不會再fork出新的子進程if(pid <= (pid_t) 0){/* child process or error*/sleep(1); /* make childs faster */break;}}// 如果創建子進程失敗,那么打印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 */// 如果不使用代理服務器,那么子進程直接對目標服務器發出http請求,否則向代理服務器發出http請求if(proxyhost==NULL)benchcore(host,proxyport,request);elsebenchcore(proxyhost,proxyport,request);/* write results to pipe */// 獲取管道寫端的文件指針f=fdopen(mypipe[1],"w");// 獲取失敗,直接退出,返回碼為3,表示內部錯誤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);// 返回0,表示運行成功return 0;} else // 父進程中{// 獲取管道讀端的指針f=fdopen(mypipe[0],"r");// 獲取失敗,直接退出,返回碼為3,表示內部錯誤if(f==NULL) {perror("open pipe for reading failed.");return 3;}// 設置不使用緩沖。每個I/O操作都被即時寫入管道setvbuf(f,NULL,_IONBF,0);// 初始化傳輸速率,測試失敗次數,傳輸總字節數都為0speed=0;failed=0;bytes=0;// 父進程循環讀取數據 while(1){// 循環從管道中每3個一組讀取子進程的輸出數據,并且獲取成功讀取的參數個數pid=fscanf(f,"%d %d %d",&i,&j,&k);// 如果成功讀取的個數小于2,說明有子進程中途掛掉,直接退出讀取循環if(pid<2){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); */// 客戶端數減一后如果等于0,說明沒有多的客戶端數據讀取,直接退出循環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; }// 子進程在測試時間內不斷向服務器建立連接并發送http請求,計時器到期后退出子線程,統計相應數據 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 */// 設置SIGALRM的信號處理函數sa.sa_handler=alarm_handler;sa.sa_flags=0;if(sigaction(SIGALRM,&sa,NULL))exit(3);// 設置計時器時間為運行測試的時間,到期后發送SIGALRM信號alarm(benchtime);// 獲取請求報文大小rlen=strlen(req);// 進入循環,每次客戶端建立一個連接,計時器時間到期后再退出nexttry:while(1){// 如果timerexpired等于1,說明收到了SIGALRM信號,表示計時器到期了,直接返回if(timerexpired){// 如果失敗的測試數大于0,那么失敗的測試數減一if(failed>0){/* fprintf(stderr,"Correcting failed by signal\n"); */failed--;}return;}// 建立與目標服務器的TCP連接s=Socket(host,port);// 如果連接失敗,測試的失敗數加一,繼續循環 if(s<0) { failed++;continue;} // 如果請求報文寫入套接字失敗,測試的失敗數加一,繼續循環if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;}// 如果使用HTTP/0.9協議,因為會在服務器回復后自動斷開連接,所以可以先關閉寫端if(http10==0) // 如果寫端關閉失敗,那么說明是不正常的連接狀態,測試的失敗數加一,關閉連接,繼續循環if(shutdown(s,1)) { failed++;close(s);continue;}// 如果設置需要等待服務器響應,那么還要處理響應數據,否則直接關閉連接if(force==0) {/* read all available data from socket */// 從套接字中讀取數據while(1){// 如果計時器到期,結束讀取if(timerexpired) break; // 將數據讀取進buf中i=read(s,buf,1500);/* fprintf(stderr,"%d\n",i); */// 如果讀取失敗,測試的失敗數加一,關閉連接,繼續循環,客戶端重新建立連接,直到計時器到期后再退出if(i<0) { failed++;close(s);goto nexttry;}else// 如果已經讀取到文件末尾,結束讀取數據if(i==0) break;// 如果讀取到了數據,將總共傳送的字節數加上讀取到的數據的字節數elsebytes+=i;}}// 關閉連接,如果失敗,測試失敗數加一,繼續循環if(close(s)) {failed++;continue;}// 傳輸速率(這里用測試成功數表示,后面除以時間得到真正的傳輸速率)加一speed++;} }

    總結

    以上是生活随笔為你收集整理的webbench源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。