打印
[应用相关]

STM32深造之——开源Webbench学习

[复制链接]
609|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Webbench是一个在linux下使用的非常简单的网站压测工具。它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能,最多可以模拟3万个并发连接去测试网站的负载能力。Webbench使用C语言编写, 代码实在太简洁,源码加起来不到600行。因此,学习Webbench的源码对于学习C语言很有帮助。

使用特权

评论回复
沙发
stm32jy|  楼主 | 2021-1-7 21:41 | 只看该作者
下载Webbench源码:下载链接:http://home.tiscali.cz/~cz210552/webbench.html

使用特权

评论回复
板凳
stm32jy|  楼主 | 2021-1-7 21:48 | 只看该作者
Webbench源码内容如下,我们重点看webbench.c文件,学习一下webbench中的C语言技巧,这在C语言的教学视频里是学不来的哦!

使用特权

评论回复
地板
stm32jy|  楼主 | 2021-1-7 21:48 | 只看该作者
建议大家直接使用VScode打开Webbench文件夹,方便函数之间的跳转和结构变量、宏定义的查询。学习任何一个C语言的软件,我们一般都是从主函数main看起,找不到尾还找不到头吗?先看一下Webbench的主函数里都干了啥?主函数太多,我们先切割着看哈!
int main(int argc, char *argv[])
{
   if(argc == 1)
   {
      usage();
        return 2;
   }
…………………….


使用特权

评论回复
5
stm32jy|  楼主 | 2021-1-7 21:50 | 只看该作者
这个大家都可以看得懂吧,其中main函数中的参数argc和argv用于运行时,把命令行参数传入主程序,判断传入参数个数为1时执行usage()函数,该函数其实就是打印一些提示字符串,这里大家注意一下,使用的是fprintf而不是printf函数,他俩有啥区别吗?printf就是标准输出,在屏幕上打印出一段字符串来;fprintf是将字符输出到流(文件)的;usage()函数中的fprintf使用stderr,对应的是标准输出;所以,两者是等效的,使用printf也是可以的。

使用特权

评论回复
6
stm32jy|  楼主 | 2021-1-7 21:51 | 只看该作者
usage()函数
void usage()
{
    fprintf(stderr,
        "webbench [option]... URL\n"
        "  -f|--force               Don't wait for reply from server.\n"
        "  -r|--reload              Send reload request - Pragma: no-cache.\n"
        "  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.\n"
        "  -p|--proxy <server:port> Use proxy server for request.\n"
        "  -c|--clients <n>         Run <n> HTTP clients at once. Default one.\n"
        "  -9|--http09              Use HTTP/0.9 style requests.\n"
        "  -1|--http10              Use HTTP/1.0 protocol.\n"
        "  -2|--http11              Use HTTP/1.1 protocol.\n"
        "  --get                    Use GET request method.\n"
        "  --head                   Use HEAD request method.\n"
        "  --options                Use OPTIONS request method.\n"
        "  --trace                  Use TRACE request method.\n"
        "  -?|-h|--help             This information.\n"
        "  -V|--version             Display program version.\n"
        );
}


使用特权

评论回复
7
stm32jy|  楼主 | 2021-1-7 21:52 | 只看该作者
第一次的实践咱们干点无聊的事,argc的值默认是多少?如果我不输入任何参数会执行usage函数吗?那我们就简单编写一部分代码,上传的Linux服务器编译测试一下。
#include <stdio.h>
……………………………………….
int main(int argc, char *argv[])
{
   if(argc == 1)
   {
      usage();
        return 2;
   }
    return 0;
}


使用特权

评论回复
8
stm32jy|  楼主 | 2021-1-7 21:55 | 只看该作者
可以看到在不输入任何参数情况下打印了一些提示字符串,证明argc默认的值是为1,如果在a.out 后面输入一个参数,此时argc为2,不会执行打印,将fprintf换成printf一样可以正常打印,这里我就不纠结使用哪个了哈!

使用特权

评论回复
9
stm32jy|  楼主 | 2021-1-7 21:55 | 只看该作者
分析了argc默认参数的问题之后,我们接着往下撸主函数,切割主函数片段2中,我们重点关注getopt_long函数,我相信对于C语言的初学者肯定没有接触过getopt_long函数,此函数和getopt函数类似,学习getopt_long之前我们先来学习一下getopt函数,getopt函数是用来解析命令行选项参数的,但是只能解析短选项:如 -d 100,不能解析长选项:如—prefix等。getopt函数原型:
int getopt(int argc, char * const argv[], const char *optstring);下边重点举例说明optstring的格式意义:例如:char*optstring = “Vt:c::”;

单个字符V          表示选项V没有参数            格式:-V即可,不加参数
单字符加冒号t:      表示选项t有且必须加参数       格式:-t 100或-t100,但-t=100错
单字符加2冒号c::   表示选项c可以有,也可以无     格式:-c200,其它格式错误

使用特权

评论回复
10
stm32jy|  楼主 | 2021-1-7 21:56 | 只看该作者
主函数切割短片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':
                /* proxy server parsing server:port */
                tmp=strrchr(optarg,':');
                proxyhost=optarg;
                if(tmp==NULL)
                {
                    break;
                }
                if(tmp==optarg)
                {
                    fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg);
                    return 2;
                }
                if(tmp==optarg+strlen(optarg)-1)
                {
                   fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg);
                    return 2;
                }
                *tmp='\0';
                proxyport=atoi(tmp+1);break;
          case ':':
          case 'h':
          case '?': usage();return 2;break;
          case 'c': clients=atoi(optarg);break;
     }
}

使用特权

评论回复
11
stm32jy|  楼主 | 2021-1-7 21:59 | 只看该作者
为了更好的理解,先简单使用getopt函数写一个伪指令代码测试一下,测试选项中912Vfr?h字符选项都不带参数,tpc字符选项需要加参数输入。
int main(int argc, char *argv[])
{
   int opt = 0;
   if(argc == 1)
   {
      usage();
        return 2;
   }
   while((opt=getopt(argc,argv,"912Vfrt:p:c:?h"))!=-1 )
    {
     switch(opt)
     {
          case  0 : break;
          case 'f': printf("f\n");break;
          case 'r': printf("r\n");break;
          case '9': printf("9\n");break;
          case '1': printf("1\n");break;
          case '2': printf("2\n");break;
          case 'V': printf("V\n");break;
          case 't': printf("t\n");break;
          case 'p': printf("p\n");break;
          case 'h': printf("h\n");break;
          case '?': printf("?\n");break;
          case 'c': printf("c\n");break;
     }
    }
    return 0;
}


使用特权

评论回复
12
stm32jy|  楼主 | 2021-1-7 22:02 | 只看该作者
测试结果可以看到,输入-f 可以得到正确的的打印,输入 –t 时由于没有加参数,会提示且打印参数错误。

使用特权

评论回复
13
stm32jy|  楼主 | 2021-1-7 22:06 | 只看该作者
对getopt函数有了一定的了解之后,我们来看一下getopt_long函数,该函数除了包含getopt功能外,还增加了解析长选项的功能如:--prefix –help  原型如下:
int getopt_long(int argc, char * const argv[], const char *optstring,
                const struct option *longopts, int*longindex);

使用特权

评论回复
14
stm32jy|  楼主 | 2021-1-7 22:09 | 只看该作者
longopts结构体中需要指明了长参数的名称和属性,longindex参数如果非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值。这里又出现了一个option结构体,改结构体在getopt.h 头文件中定义如下:
struct option {
const char  *name;       /* 参数名称 */
int          has_arg;     /* 指明是否带有参数 */
int          *flag;        /* flag=NULL时,返回value;不为空时,*flag=val,返回0 */
int          val;          /* 用于指定函数找到选项的返回值或flag非空时指定*flag的值 */
};

使用特权

评论回复
15
stm32jy|  楼主 | 2021-1-7 22:11 | 只看该作者
接着使用option结构体定义了long_options结构体数组,具体内容如下:
#define METHOD_GET 0
#define METHOD_HEAD 1
#define METHOD_OPTIONS 2
#define METHOD_TRACE 3

int method=METHOD_GET;
int force=0;
int force_reload=0;

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}
};


使用特权

评论回复
16
stm32jy|  楼主 | 2021-1-7 22:12 | 只看该作者
getopt_long函数测试
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>

#define METHOD_GET 0
#define METHOD_HEAD 1
#define METHOD_OPTIONS 2
#define METHOD_TRACE 3

int method=METHOD_GET;
int force=0;
int force_reload=0;

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}
};
void usage()
{
    printf(
        "webbench [option]... URL\n"
        "  -f|--force               Don't wait for reply from server.\n"
        "  -r|--reload              Send reload request - Pragma: no-cache.\n"
        "  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.\n"
        "  -p|--proxy <server:port> Use proxy server for request.\n"
        "  -c|--clients <n>         Run <n> HTTP clients at once. Default one.\n"
        "  -9|--http09              Use HTTP/0.9 style requests.\n"
        "  -1|--http10              Use HTTP/1.0 protocol.\n"
        "  -2|--http11              Use HTTP/1.1 protocol.\n"
        "  --get                    Use GET request method.\n"
        "  --head                   Use HEAD request method.\n"
        "  --options                Use OPTIONS request method.\n"
        "  --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 longindex = 0;
   if(argc == 1)
   {
      usage();
        return 2;
   }
   while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&longindex))!=-1 )
    {
     switch(opt)
     {
          case  0 : break;
          case 'f': printf("f\n");break;
          case 'r': printf("r\n");break;
          case '9': printf("9\n");break;
          case '1': printf("1\n");break;
          case '2': printf("2\n");break;
          case 'V': printf("V\n");exit(0);
          case 't': printf("t\n");break;
          case 'p': printf("p\n");break;
          case ':': printf(":\n");break;
          case 'h': printf("h\n");break;
          case '?': usage();break;
          case 'c': printf("c\n");break;
     }
    }
    return 0;
}


使用特权

评论回复
17
stm32jy|  楼主 | 2021-1-7 22:15 | 只看该作者
测试结果如下

使用特权

评论回复
18
xiaoqizi| | 2021-2-3 20:46 | 只看该作者
什么机构的视频教学啊

使用特权

评论回复
19
木木guainv| | 2021-2-3 20:48 | 只看该作者
非常感谢楼主分享的资料

使用特权

评论回复
20
磨砂| | 2021-2-3 20:49 | 只看该作者
可以用来对stm干嘛啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

1118

帖子

4

粉丝