概述
上一章记录了源码的获取和使用,接下来开始记录源码分析过程。本章主要是分析main
函数结构,然后具体解析下getopt_long
和build_request
两个函数的主要内容。
1. main函数结构
- 判断传入参数的个数,如果没有参数,则打印菜单。
- 通过while循环检索参数,对程序进行配置。
- 调用build_request函数
- 根据设置结果,打印参数信息
- 调用bench函数
在接下来的几篇文章中,主要是对上述标注的三个部分进行分析。
2.getopt_long函数
getopt_long
函数原型为:
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
程序中调用如下:
while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF )
该函数分为三个部分讲解。
2.1. 函数调用的几个参数
2.1.1. argc
参数个数
2.1.2. argv
参数内容
2.1.3. optstring
“912Vfrt:p:c:?h”:程序支持的命令行短选项。也就是命令行中支持-9、-1、-2、-V、-f、-r、-t、-p、-c、-?、-h
十一个短选项,其中t、p、c三个字符后面有一个冒号,表示t、p、c应带有一个参数。如Webbench学习笔记一:源码获取和使用测试运行部分使用的命令行:
webbench -c 1000 -t 60 http://test.domain.com/phpinfo.php
2.1.4. longopts
long_options:是一个option 类型的数组,表示程序支持的命令行长选项。其定义如下:
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}
};
option定义如下:
struct option
{
const char *name;
int has_arg;
int *flag;
int val;
};
(1)name:表示选项的名称,比如force,reload,time等。
(2)has_arg:表示选项后面是否携带参数。
a: no_argument(或者是0)时 ——参数后面不跟参数值,eg: --force,--reload
b: required_argument(或者是1)时 ——参数输入格式为:--参数 值 或者 --参数=值。eg:--time=60
c: optional_argument(或者是2)时 ——参数输入格式只能为:--参数=值。这里没有用到。
(3)flag:这个参数有两个意思,空或者非空。
a:如果参数为空NULL,那么当选中某个长选项的时候,getopt_long将返回val值。 eg,可执行程序 --time,getopt_long的返回值为t.
b:如果参数不为空,那么当选中某个长选项的时候,getopt_long将返回0,并且将flag指针参数指向val值。 eg: 可执行程序 --force=1 那么getopt_long返回值为0,并且force值为1。
(4)val:表示指定函数找到该选项时的返回值,或者当flag非空时指定flag指向的数据的值val。
2.1.5. longindex
options_index:非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值。
2.2 四个全局变量
2.2.1. optarg
表示当前选项对应的参数值。从下面代码可以看出:
case 't': benchtime=atoi(optarg);break;
//webbench -c 1000 -t 60 http://test.domain.com/phpinfo.php
//此处即将60赋值给benchtime
2.2.2. optind
表示的是下一个将被处理到的参数在argv中的下标值。相关代码如下:
if(optind==argc) {
fprintf(stderr,"webbench: Missing URL!\n");
usage();
return 2;
}
这个if判断在下一节的返回值说明。
2.2.3. opterr
如果opterr = 0,getopt_long遇到错误将不会输出错误信息到标准输出流。opterr在非0时,向屏幕输出错误。
程序内未使用。
2.2.4. optopt
表示没有被未标识的选项。
程序内未使用
参考链接:浅谈linux的命令行解析参数之getopt_long函数。
2.3. 函数返回值
webbench -c 1000 -t 60 http://test.domain.com/phpinfo.php
while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF )
这句话的意思是检索参数选项。结合
第一次执行:
opt = c //c为支持的短选项,getopt_long返回c
optarg = 1000 //选项c对应的参数值
optind = 3 //下一个将被处理的参数下标值为3,即-t
argv[optind - 1] = 1000
第二次执行:
opt = t //t为支持的短选项,getopt_long返回t
optarg = 60 //选项t对应的参数值
optind = 5 //下一个将被处理的参数下标值为5,即http://test.domain.com/phpinfo.php
argv[optind - 1] = 60
第三次执行:
http://test.domain.com/phpinfo.php不是支持的短选项或长选项,所以返回-1,退出while循环。
EOF实际是-1,用来表示文本文件的结束
此时optind = 5
而传入的参数个数argc=6
,所以也就有了
if(optind==argc) {
fprintf(stderr,"webbench: Missing URL!\n");
usage();
return 2;
}
如果执行时未传入URL,则执行两次后结束,optind、argc= 5,也就会打印错误信息:webbench: Missing URL!
参考链接:getopt和getopt_long函数。
3.build_request函数
build_request
函数定义和调用如下:
void build_request(const char *url)
build_request(argv[optind]);
形参为一个字符串。通过上一篇的分析可以看出,此处传入的argv[optind]即执行时的URL:http://test.domain.com/phpinfo.php
3.1.字符串相关函数
build_request
函数中使用到了较多的字符串处理函数,我这里先对相关的函数进行下温习。
3.1.1.strcat
语法:
#include <string.h>
char *strcat( char *str1, const char *str2 );
功能:函数将字符串str2 连接到str1的末端,并返回指针str1.
3.1.2.strstr
语法:
#include <string.h>
char *strstr( const char *str1, const char *str2 );
功能:函数返回一个指针,它指向字符串str2 首次出现于字符串str1中的位置,如果没有找到,返回NULL。
3.1.3.strncasecmp
语法:
#include <string.h>
int strncasecmp(const char *s1, const char *s2, size_t n);
函数说明:strncasecmp()用来比较参数s1 和s2 字符串前n个字符,比较时会自动忽略大小写的差异。
返回值:若参数s1 和s2 字符串相同则返回0。s1 若大于s2 则返回大于0 的值,s1 若小于s2 则返回小于0 的值。
3.1.4.strrchr和strchr
语法:
#include <string.h>
char *strrchr( const char *str, int ch );
#include <string.h>
char *strchr( const char *str, int ch );
strrchr功能:函数返回一个指针,它指向字符ch 在字符串str末次出现的位置,如果匹配失败,返回NULL。
strchr功能:函数返回一个指向str 中ch 首次出现的位置,当没有在str 中找ch到返回NULL。
3.1.5.index
语法:
#include<strings.h>
char *index(const char *s, int c);
函数说明:
找出参数s字符串中第一个出现参数c的地址,然后将该字符串出现的地址返回。字符串结束字符(NULL)也视为字符串的一部分。
返回值:
如果找到指定的字符,则返回字符所在地址,否则返回NULL
3.1.6.strncpy
语法:
#include <string.h>
char *strncpy( char *to, const char *from, size_t count );
功能:将字符串from 中至多count个字符复制到字符串to中。如果字符串from 的长度小于count,其余部分用’\0’填补。返回处理完成的字符串。
3.2.
目的是对url进行处理,得到host,proxyport,request
其中request就是之后利用socket与host通信所要发送的报文。
fdopen
fopen
语法:
#include <stdio.h>
FILE *fopen( const char *fname, const char *mode );
fopen()函数打开由fname(文件名)指定的文件, 并返回一个关联该文件的流.如果发生错误, fopen()返回NULL. mode(方式)是用于决定文件的用途(例如 用于输入,输出,等等)
#include <stdio.h>
FILE * fdopen(int fildes, const char * mode);