webbench源码学习笔记
学习内容
一共五百多行代码,其中包含了linux编程常用的API。可以通过学习源码,把不熟悉的API练习练习。
1 如何使用webbench
(1)查看参数帮助
(2)运行方法
即以上模拟30个客户端在30秒期间并发请求百度,结果如下:
每分钟平均有1532次请求连接,服务器每秒传输字节为4039230,在30秒期间请求连接成功为766次,失败0次。
2 源码常用函数练习
(1) 选项参数
int getopt_long(int argc, char * const argv[],const char *optstring, const struct option *longopts,int *longindex);
函数中的argc和argv通常直接从main()的两个参数传递而来。optsting是选项参数组成的字符串:
option结构数组,option结构称为长选项表,其声明如下:
struct option
{
const char *name;
int has_arg;
int *flag;
int val;
};
结构中的元素解释如下:
const char *name:选项名,前面没有短横线。譬如"help"、"verbose"之类。
int has_arg:描述长选项是否有选项参数,如果有,是哪种类型的参数,其值见下表: 符号常量 数值
含义
no_argument 0 选项没有参数
required_argument 1 选项需要参数
optional_argument 2 选项参数是可选的
int *flag:
如果该指针为NULL,那么getopt_long返回val字段的值;
如果该指针不为NULL,那么会使得它所指向的结构填入val字段的值,同时getopt_long返回0 int val:
如果flag是NULL,那么val通常是个字符常量,如果短选项和长选项一致,那么该字符就应该与optstring中
字符串optstring可以下列元素:
1.单个字符,表示选项,
2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。
3 单个字符后跟两个冒号,表示该选项后可以有参数也可以没有参数。如果有参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张)。
optstring是一个字符串,表示可以接受的参数。例如,"a:b:cd",表示可以接受的参数是a,b,c,d,其中,a和b参数后面跟有更多的参数值。(例如:-a host --b name)
最后一个参数:longindex参数一般赋为NULL即可;如果没有设置为NULL,那么它就指向一个变量,这个变量会被赋值为寻找到的长选项在longopts中的索引值,这可以用于错误诊断。
函数使用方法:
1 1 #include <getopt.h> 2 2 3 3 #include <stdio.h> 4 4 5 5 #include <stdlib.h> 6 6 7 7 8 8 9 9 static const char *program =NULL; 10 10 11 11 12 12 13 13 static const struct option long_opts[] = { 14 14 15 15 {"help", no_argument, NULL, 'h'}, 16 16 17 17 {"version", no_argument, NULL, 'v'}, 18 18 19 19 {"author", required_argument, NULL, 'a'}, 20 20 21 21 {"date", no_argument, NULL, 'd'}, 22 22 23 23 {"time", no_argument, NULL, 't'}, 24 24 25 25 {0, 0, 0} 26 26 27 27 }; 28 28 29 29 void usage() 30 30 31 31 { 32 32 33 33 printf("argument: \n"); 34 34 35 35 printf("\t --version,-v \n" 36 36 37 37 "\t --author, -a\n" 38 38 39 39 "\t --date, -d\n" 40 40 41 41 "\t --time, -t\n" 42 42 43 43 "\t --help, -h\n" 44 44 45 45 ); 46 46 47 47 } 48 48 49 49 50 50 51 51 int main(int argc,char* argv[]) 52 52 53 53 { 54 54 55 55 char *str; 56 56 57 57 int long_index,c,ret; 58 58 59 59 program = argv[0]; 60 60 61 61 while((c=getopt_long(argc, argv, "hva:dt", long_opts, &long_index))!=EOF){ 62 62 63 63 switch(c){ 64 64 65 65 case 'h': 66 66 67 67 usage(); 68 68 69 69 exit(0); 70 70 71 71 case 'v': 72 72 73 73 printf("version 1.2.0\n"); 74 74 75 75 break; 76 76 77 77 case 'a': 78 78 79 79 str=optarg; 80 80 81 81 printf("author is %s\n",str); 82 82 83 83 break; 84 84 85 85 case 'd': 86 86 87 87 printf("date is 2016.10.20\n"); 88 88 89 89 break; 90 90 91 91 case 't': 92 92 93 93 printf("time is 12:30:45\n"); 94 94 95 95 break; 96 96 97 97 default: 98 98 99 99 printf("ERR: please try: %s -h\n", program); 100 100 101 101 exit(0); 102 102 103 103 } 104 104 105 105 } 106 106 107 107 return 0; 108 108 109 109 } 110 (2)字符串相关API 111 112 strlen()//字符串长度 113 114 bzero()//清空 115 116 strstr()//子串查找 117 118 strncpy()//复制 119 120 strcat()//拼接 121 122 1 #include <stdio.h> 123 2 #include <string.h> 124 3 #include <errno.h> 125 4 126 5 int main(void) 127 6 { 128 7 char string[20]; 129 8 char *str1="nihao"; 130 9 strncpy(string,str1,3); 131 10 string[3]='\0';//字符串末尾0 132 11 printf("%s\n",string); 133 12 //strcat(str1,str2) 134 13 char destnination[25]; 135 14 char *blank="",*c="python",*borland="boland"; 136 15 strcpy(destnination,borland); 137 16 strcat(destnination,blank); 138 17 strcat(destnination,c); 139 18 printf("%s\n",destnination); 140 19 141 20 //strncat(str1,str2,n) 142 21 char url[100]="http://www.baidu.com"; 143 22 char path[20]="/cpp/string"; 144 23 strncat(url,path,100);//100超过了path的长度 145 24 printf("%s\n",url); 146 25 147 26 148 27 //strlen(str) 149 28 char str[5]="abcd"; 150 29 printf("strlen(str)=%d,sizeof(str)=%d",strlen(str),sizeof(str));//4 5 151 30 152 31 //strcmp 相等饭回0 str1大于str2 饭回正数 153 32 char *a="aBcDeE"; 154 33 char *b="AbCdEf"; 155 34 printf("strcmp(a,b):%d\n",strcmp(a,b)); 156 35 157 36 158 37 //strchr(str,c) 在str字符串中查找首次出现字符c的位置 159 38 char *s3="123445555656"; 160 39 char *p5; 161 40 p5=strchr(s3,'5'); 162 41 163 42 printf("%ld\n",s3); 164 43 165 44 //strpbrk(str1,str2) 依次检验字符串str1的字符 当被检验字符在字符串str2中也包含的时候则停止检验 返回这个字符的位置 166 45 char *s1="see you again"; 167 46 char *s2 = "you"; 168 47 char *p=strpbrk(s1,s2); 169 48 if(p) 170 49 { 171 50 printf("the result is:%s\n",p); 172 51 }else 173 52 { 174 53 printf("sorry\n"); 175 54 } 176 55 177 56 //atoi(str) 字符串转换为int整数 178 57 //strstr 检索子串在字符串首次出现的位置 179 58 char *str5="hellodfdflhellop"; 180 59 char *substr="hello"; 181 60 char *s=strstr(str5,substr); 182 61 printf("%s\n",s); 183 62 184 63 //strerror 返回指向错误信息字符串的指针 185 64 char *buffer2=NULL; 186 65 buffer2=strerror(errno); 187 66 printf("Error:%s\n",buffer2); 188 67 189 68 //bzero(void *s,int n) 190 69 struct 191 70 { 192 71 int a; 193 72 char s[5]; 194 73 float f; 195 74 }tt; 196 75 char ss[20]; 197 76 bzero(&tt,sizeof(tt)); 198 77 bzero(ss,20);//等价于memset(s,0,20) 199 78 return 0; 200 79 201 80 202 81 203 82 204 83 }
(3)信号相关API
案例https://www.cnblogs.com/yxk529188712/p/4983565.html
(4)IO相关
fwrite()
fread()
read()
(5)管道
int pipe(int fd[2]) 成功返回0,失败返回-1
管道和有名管道是进程间通信机制之一
管道是半双工,所以双方通信需要建立两个通道
FILE * fdopen(int fildes,const char * mode);
fdopen取一个现存的文件描述符(我 们可能从 o p e n , d u p , d u p 2 , f c n t l或p i p e函数得到此文件描述符) ,并使一个标准的I / O流与该描述符相结合。此函数常用于由创建管道和网络通信通道函数获得的描述符。因为这些特殊类型的文件不能用标准I/O fopen函数打开,首先必须先调用设备专用函数以获得一个文件描述符,然后用f d o p e n使一个标准I / O流与该描述符相结合。
fdopen()会将参数fildes 的文件描述符,转换为对应的文件指针后返回。参数mode 字符串 则代表着文件指针的流形态,此形态必须和原先文件描述词读写模式相同。
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <string.h> 4 #include <stdlib.h> 5 int main(int argc,char *argv[]) 6 { 7 char buf[1024]; 8 int fds[2],fds2[2]; //fds[0]用于读 fds[1]用于写 9 pipe(fds); 10 pipe(fds2); 11 if(fork()>0)//父亲进程 12 { 13 close(fds[1]);//读的时候应先关闭写 14 close(fds2[0]); //写的时候先关闭读 15 while(memset(buf,0,1024),read(fds[0],buf,1024)>0)//从管道读 16 { 17 write(1,buf,strlen(buf)); //read是一个阻塞函数,会一直停在这里 18 } 19 close(fds[2]); //要使用close关闭管道 管道也会堵塞 20 21 22 printf("father speaking:\n"); 23 FILE *fs=fdopen(fds2[1],"w");//管道与文件指针建立连接 可以不实用文件指针直接对管道操作 24 if(fs==NULL) //while(memset(buf,0,1024),read(0,buf,1024)>0) 25 { //{ write(fds[1],buf,strlen(buf));} 26 perror("father died!\n"); 27 } 28 while(memset(buf,0,1024),fgets(buf,1024,stdin)!=NULL)//输入buf中 29 { 30 fprintf(fs,"father message:%s",buf);//写入文件 31 fflush(fs); 32 } 33 close(fds2[1]); 34 wait(NULL); 35 } 36 else 37 { 38 close(fds[0]); 39 close(fds2[1]);//关闭写 40 FILE *fd=fdopen(fds[1],"w");//管道当作一个文件 41 if(fd==NULL) 42 { 43 perror("fdopen wrong\n"); 44 } 45 while(memset(buf,0,1024),fgets(buf,1024,stdin)!=NULL) 46 { 47 fprintf(fd,"child message:%s",buf); 48 fflush(fd); 49 } 50 close(fds[1]); 51 52 while(memset(buf,0,1024),read(fds2[0],buf,1024)>0) 53 { 54 write(1,buf,strlen(buf)); 55 } 56 close(fds2[0]); 57 exit(1); 58 } 59 return 0; 60 }
2 执行流程
3 源码注释
1 /* 2 * (C) Radim Kolar 1997-2004 3 * This is free software, see GNU Public License version 2 for 4 * details. 5 * 6 * Simple forking WWW Server benchmark: 7 * 8 * Usage: 9 * webbench --help 10 * 11 * Return codes: 12 * 0 - sucess 13 * 1 - benchmark failed (server is not on-line) 14 * 2 - bad param 15 * 3 - internal error, fork failed 16 * 17 */ 18 19 #include "socket.c" 20 #include <unistd.h> 21 #include <sys/param.h> 22 #include <rpc/types.h> 23 #include <getopt.h> 24 #include <strings.h> 25 #include <time.h> 26 #include <signal.h> 27 28 /* values */ 29 volatile int timerexpired=0; 30 int speed=0; 31 int failed=0; 32 int bytes=0; 33 34 /* globals */ 35 int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */ 36 /* Allow: GET, HEAD, OPTIONS, TRACE */ 37 #define METHOD_GET 0 38 #define METHOD_HEAD 1 39 #define METHOD_OPTIONS 2 40 #define METHOD_TRACE 3 41 #define PROGRAM_VERSION "1.5" 42 int method=METHOD_GET; 43 int clients=1; 44 int force=0; 45 int force_reload=0; 46 int proxyport=80; 47 char *proxyhost=NULL; 48 int benchtime=30; 49 50 /* internal */ 51 int mypipe[2]; 52 char host[MAXHOSTNAMELEN]; 53 #define REQUEST_SIZE 2048 54 char request[REQUEST_SIZE]; 55 56 static const struct option long_options[]= 57 { 58 {"force",no_argument,&force,1}, 59 {"reload",no_argument,&force_reload,1}, 60 {"time",required_argument,NULL,'t'}, 61 {"help",no_argument,NULL,'?'}, 62 {"http09",no_argument,NULL,'9'}, 63 {"http10",no_argument,NULL,'1'}, 64 {"http11",no_argument,NULL,'2'}, 65 {"get",no_argument,&method,METHOD_GET}, 66 {"head",no_argument,&method,METHOD_HEAD}, 67 {"options",no_argument,&method,METHOD_OPTIONS}, 68 {"trace",no_argument,&method,METHOD_TRACE}, 69 {"version",no_argument,NULL,'V'}, 70 {"proxy",required_argument,NULL,'p'}, 71 {"clients",required_argument,NULL,'c'}, 72 {NULL,0,NULL,0} 73 }; 74 75 /* prototypes */ 76 static void benchcore(const char* host,const int port, const char *request); 77 static int bench(void); 78 static void build_request(const char *url); 79 80 static void alarm_handler(int signal) 81 { 82 timerexpired=1; 83 } 84 85 static void usage(void) 86 { 87 fprintf(stderr, 88 "webbench [option]... URL\n" 89 " -f|--force Don't wait for reply from server.\n" 90 " -r|--reload Send reload request - Pragma: no-cache.\n" 91 " -t|--time <sec> Run benchmark for <sec> seconds. Default 30.\n" 92 " -p|--proxy <server:port> Use proxy server for request.\n" 93 " -c|--clients <n> Run <n> HTTP clients at once. Default one.\n" 94 " -9|--http09 Use HTTP/0.9 style requests.\n" 95 " -1|--http10 Use HTTP/1.0 protocol.\n" 96 " -2|--http11 Use HTTP/1.1 protocol.\n" 97 " --get Use GET request method.\n" 98 " --head Use HEAD request method.\n" 99 " --options Use OPTIONS request method.\n" 100 " --trace Use TRACE request method.\n" 101 " -?|-h|--help This information.\n" 102 " -V|--version Display program version.\n" 103 ); 104 } 105 106 int main(int argc, char *argv[]) 107 { 108 int opt=0; 109 int options_index=0; 110 char *tmp=NULL; 111 112 if(argc==1) 113 { 114 usage(); 115 return 2; 116 } 117 //getopt_long 参数处理 根据不同的选项对应不同的操作 118 while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF ) 119 { 120 switch(opt) 121 { 122 case 0 : break; 123 case 'f': force=1;break; 124 case 'r': force_reload=1;break; 125 case '9': http10=0;break; 126 case '1': http10=1;break; 127 case '2': http10=2;break; 128 case 'V': printf(PROGRAM_VERSION"\n");exit(0); 129 case 't': benchtime=atoi(optarg);break; 130 case 'p': 131 /* proxy server parsing server:port */ 132 tmp=strrchr(optarg,':'); 133 proxyhost=optarg; 134 if(tmp==NULL) 135 { 136 break; 137 } 138 if(tmp==optarg) 139 { 140 fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg); 141 return 2; 142 } 143 if(tmp==optarg+strlen(optarg)-1) 144 { 145 fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg); 146 return 2; 147 } 148 *tmp='\0'; 149 proxyport=atoi(tmp+1);break; 150 case ':': 151 case 'h': 152 case '?': usage();return 2;break; 153 case 'c': clients=atoi(optarg);break; 154 } 155 } 156 157 if(optind==argc) { 158 fprintf(stderr,"webbench: Missing URL!\n"); 159 usage(); 160 return 2; 161 } 162 //默认clients用户为1 163 if(clients==0) 164 clients=1; 165 //默认压测30s 166 if(benchtime==0) 167 benchtime=30; 168 169 /* Copyright */ 170 fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n" 171 "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n" 172 ); 173 //构造请求 174 build_request(argv[optind]); 175 176 // print request info ,do it in function build_request 177 /*printf("Benchmarking: "); 178 179 switch(method) 180 { 181 case METHOD_GET: 182 default: 183 printf("GET");break; 184 case METHOD_OPTIONS: 185 printf("OPTIONS");break; 186 case METHOD_HEAD: 187 printf("HEAD");break; 188 case METHOD_TRACE: 189 printf("TRACE");break; 190 } 191 192 printf(" %s",argv[optind]); 193 194 switch(http10) 195 { 196 case 0: printf(" (using HTTP/0.9)");break; 197 case 2: printf(" (using HTTP/1.1)");break; 198 } 199 200 printf("\n"); 201 */ 202 203 printf("Runing info: "); 204 205 if(clients==1) 206 printf("1 client"); 207 else 208 printf("%d clients",clients); 209 210 printf(", running %d sec", benchtime); 211 212 if(force) 213 printf(", early socket close"); 214 if(proxyhost!=NULL) 215 printf(", via proxy server %s:%d",proxyhost,proxyport); 216 if(force_reload) 217 printf(", forcing reload"); 218 219 printf(".\n"); 220 221 return bench(); 222 } 223 224 //构造请求 225 void build_request(const char *url) 226 { 227 char tmp[10]; 228 int i; 229 230 //bzero(host,MAXHOSTNAMELEN); 231 //bzero(request,REQUEST_SIZE); 232 memset(host,0,MAXHOSTNAMELEN); 233 memset(request,0,REQUEST_SIZE); 234 235 if(force_reload && proxyhost!=NULL && http10<1) 236 http10=1; 237 if(method==METHOD_HEAD && http10<1) 238 http10=1; 239 if(method==METHOD_OPTIONS && http10<2) 240 http10=2; 241 if(method==METHOD_TRACE && http10<2) 242 http10=2; 243 //不同的构造头方法 244 /* 245 http头部格式 246 请求方法 空格 URL 空格 协议版本 \r\n 247 头部字段名 值 \r\n 248 \r\n 249 */ 250 switch(method) 251 { 252 default: 253 case METHOD_GET: strcpy(request,"GET");break; 254 case METHOD_HEAD: strcpy(request,"HEAD");break; 255 case METHOD_OPTIONS: strcpy(request,"OPTIONS");break; 256 case METHOD_TRACE: strcpy(request,"TRACE");break; 257 } 258 259 strcat(request," "); 260 261 if(NULL==strstr(url,"://")) 262 { 263 fprintf(stderr, "\n%s: is not a valid URL.\n",url); 264 exit(2); 265 } 266 //url限制大小为1500 267 if(strlen(url)>1500) 268 { 269 fprintf(stderr,"URL is too long.\n"); 270 exit(2); 271 } 272 if (0!=strncasecmp("http://",url,7)) 273 { 274 fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n"); 275 exit(2); 276 } 277 278 /* protocol/host delimiter */ 279 i=strstr(url,"://")-url+3; 280 281 if(strchr(url+i,'/')==NULL) { 282 fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n"); 283 exit(2); 284 } 285 286 if(proxyhost==NULL) 287 { 288 /* get port from hostname */ 289 if(index(url+i,':')!=NULL && index(url+i,':')<index(url+i,'/')) 290 { 291 strncpy(host,url+i,strchr(url+i,':')-url-i); 292 //bzero(tmp,10); 293 memset(tmp,0,10); 294 strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1); 295 /* printf("tmp=%s\n",tmp); */ 296 proxyport=atoi(tmp); 297 if(proxyport==0) proxyport=80; 298 } 299 else 300 { 301 strncpy(host,url+i,strcspn(url+i,"/")); 302 } 303 // printf("Host=%s\n",host); 304 strcat(request+strlen(request),url+i+strcspn(url+i,"/")); 305 } 306 else 307 { 308 // printf("ProxyHost=%s\nProxyPort=%d\n",proxyhost,proxyport); 309 strcat(request,url); 310 } 311 312 if(http10==1) 313 strcat(request," HTTP/1.0"); 314 else if (http10==2) 315 strcat(request," HTTP/1.1"); 316 317 strcat(request,"\r\n"); 318 //到这里头部构造完成 319 320 if(http10>0) 321 strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n"); 322 if(proxyhost==NULL && http10>0) 323 { 324 strcat(request,"Host: "); 325 strcat(request,host); 326 strcat(request,"\r\n"); 327 } 328 329 if(force_reload && proxyhost!=NULL) 330 { 331 strcat(request,"Pragma: no-cache\r\n"); 332 } 333 334 if(http10>1) 335 strcat(request,"Connection: close\r\n"); 336 337 /* add empty line at end */ 338 if(http10>0) 339 strcat(request,"\r\n"); 340 341 printf("\nRequest:\n%s\n",request); 342 } 343 344 /* vraci system rc error kod */ 345 static int bench(void) 346 { 347 int i,j,k; 348 pid_t pid=0; 349 FILE *f; 350 351 /* check avaibility of target server */ 352 i=Socket(proxyhost==NULL?host:proxyhost,proxyport); 353 if(i<0) { 354 fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n"); 355 return 1; 356 } 357 close(i); 358 359 /* 创建管道 */ 360 if(pipe(mypipe)) 361 { 362 perror("pipe failed."); 363 return 3; 364 } 365 366 /* not needed, since we have alarm() in childrens */ 367 /* wait 4 next system clock tick */ 368 /* 369 cas=time(NULL); 370 while(time(NULL)==cas) 371 sched_yield(); 372 */ 373 374 /* fork childs */ 375 //多少个用户多少个进程 fork一次返回两个 376 for(i=0;i<clients;i++) 377 { 378 pid=fork(); 379 if(pid <= (pid_t) 0) 380 { 381 /* child process or error*/ 382 sleep(1); /* make childs faster */ 383 break; 384 } 385 } 386 387 if( pid < (pid_t) 0) 388 { 389 fprintf(stderr,"problems forking worker no. %d\n",i); 390 perror("fork failed."); 391 return 3; 392 } 393 //如果是子进程 394 395 if(pid == (pid_t) 0) 396 { 397 /* I am a child */ 398 if(proxyhost==NULL) 399 benchcore(host,proxyport,request); 400 else 401 benchcore(proxyhost,proxyport,request); 402 403 /* write results to pipe */ 404 //构造完请求得到结果写入管道 405 f=fdopen(mypipe[1],"w"); 406 if(f==NULL) 407 { 408 perror("open pipe for writing failed."); 409 return 3; 410 } 411 /* fprintf(stderr,"Child - %d %d\n",speed,failed); */ 412 fprintf(f,"%d %d %d\n",speed,failed,bytes); 413 fclose(f); 414 415 return 0; 416 } 417 else 418 { 419 //父进程从管道读数据 420 f=fdopen(mypipe[0],"r"); 421 if(f==NULL) 422 { 423 perror("open pipe for reading failed."); 424 return 3; 425 } 426 427 setvbuf(f,NULL,_IONBF,0);//不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略 428 429 speed=0; 430 failed=0; 431 bytes=0; 432 433 while(1) 434 { 435 pid=fscanf(f,"%d %d %d",&i,&j,&k); 436 if(pid<2) 437 { 438 fprintf(stderr,"Some of our childrens died.\n"); 439 break; 440 } 441 442 speed+=i; 443 failed+=j; 444 bytes+=k; 445 446 /* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); */ 447 if(--clients==0) 448 break; 449 } 450 451 fclose(f); 452 453 printf("\nSpeed=%d pages/min, %d bytes/sec.\nRequests: %d susceed, %d failed.\n", 454 (int)((speed+failed)/(benchtime/60.0f)), 455 (int)(bytes/(float)benchtime), 456 speed, 457 failed); 458 } 459 460 return i; 461 } 462 463 void benchcore(const char *host,const int port,const char *req) 464 { 465 int rlen; 466 char buf[1500]; 467 int s,i; 468 struct sigaction sa; 469 470 /* setup alarm signal handler */ 471 sa.sa_handler=alarm_handler; 472 sa.sa_flags=0; 473 if(sigaction(SIGALRM,&sa,NULL)) 474 exit(3); 475 476 alarm(benchtime); // after benchtime,then exit 477 478 rlen=strlen(req); 479 nexttry:while(1) 480 { 481 if(timerexpired) 482 { 483 if(failed>0) 484 { 485 /* fprintf(stderr,"Correcting failed by signal\n"); */ 486 failed--; 487 } 488 return; 489 } 490 491 s=Socket(host,port); //尝试连接 492 //失败次数统计 493 if(s<0) 494 { 495 failed++; 496 continue; 497 } 498 499 if(rlen!=write(s,req,rlen)) 500 { 501 failed++; 502 close(s); 503 continue; 504 } 505 if(http10==0) 506 if(shutdown(s,1)) 507 { 508 failed++; 509 close(s); 510 continue; 511 } 512 if(force==0) 513 { 514 /* read all available data from socket */ 515 while(1) 516 { 517 if(timerexpired) break; 518 i=read(s,buf,1500); 519 /* fprintf(stderr,"%d\n",i); */ 520 if(i<0) 521 { 522 failed++; 523 close(s); 524 goto nexttry; 525 } 526 else 527 if(i==0) 528 break; 529 else 530 bytes+=i;//read返回的是字节数 所以在此可以统计字节数 531 } 532 } 533 if(close(s)) 534 { 535 failed++; 536 continue; 537 } 538 speed++; 539 } 540 }