[应用相关] STM32深造之——开源Webbench学习

[复制链接]
906|22
 楼主| stm32jy 发表于 2021-1-7 21:41 | 显示全部楼层 |阅读模式
Webbench是一个在linux下使用的非常简单的网站压测工具。它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能,最多可以模拟3万个并发连接去测试网站的负载能力。Webbench使用C语言编写, 代码实在太简洁,源码加起来不到600行。因此,学习Webbench的源码对于学习C语言很有帮助。

 楼主| stm32jy 发表于 2021-1-7 21:41 | 显示全部楼层
下载Webbench源码:下载链接:http://home.tiscali.cz/~cz210552/webbench.html
676175ff70f85cf722.png
 楼主| stm32jy 发表于 2021-1-7 21:48 | 显示全部楼层
Webbench源码内容如下,我们重点看webbench.c文件,学习一下webbench中的C语言技巧,这在C语言的教学视频里是学不来的哦!
454645ff70fb5e423b.png
 楼主| stm32jy 发表于 2021-1-7 21:48 | 显示全部楼层
建议大家直接使用VScode打开Webbench文件夹,方便函数之间的跳转和结构变量、宏定义的查询。学习任何一个C语言的软件,我们一般都是从主函数main看起,找不到尾还找不到头吗?先看一下Webbench的主函数里都干了啥?主函数太多,我们先切割着看哈!
  1. int main(int argc, char *argv[])
  2. {
  3.    if(argc == 1)
  4.    {
  5.       usage();
  6.         return 2;
  7.    }
  8. …………………….


 楼主| stm32jy 发表于 2021-1-7 21:50 | 显示全部楼层
这个大家都可以看得懂吧,其中main函数中的参数argc和argv用于运行时,把命令行参数传入主程序,判断传入参数个数为1时执行usage()函数,该函数其实就是打印一些提示字符串,这里大家注意一下,使用的是fprintf而不是printf函数,他俩有啥区别吗?printf就是标准输出,在屏幕上打印出一段字符串来;fprintf是将字符输出到流(文件)的;usage()函数中的fprintf使用stderr,对应的是标准输出;所以,两者是等效的,使用printf也是可以的。
 楼主| stm32jy 发表于 2021-1-7 21:51 | 显示全部楼层
usage()函数
  1. void usage()
  2. {
  3.     fprintf(stderr,
  4.         "webbench [option]... URL\n"
  5.         "  -f|--force               Don't wait for reply from server.\n"
  6.         "  -r|--reload              Send reload request - Pragma: no-cache.\n"
  7.         "  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.\n"
  8.         "  -p|--proxy <server:port> Use proxy server for request.\n"
  9.         "  -c|--clients <n>         Run <n> HTTP clients at once. Default one.\n"
  10.         "  -9|--http09              Use HTTP/0.9 style requests.\n"
  11.         "  -1|--http10              Use HTTP/1.0 protocol.\n"
  12.         "  -2|--http11              Use HTTP/1.1 protocol.\n"
  13.         "  --get                    Use GET request method.\n"
  14.         "  --head                   Use HEAD request method.\n"
  15.         "  --options                Use OPTIONS request method.\n"
  16.         "  --trace                  Use TRACE request method.\n"
  17.         "  -?|-h|--help             This information.\n"
  18.         "  -V|--version             Display program version.\n"
  19.         );
  20. }


 楼主| stm32jy 发表于 2021-1-7 21:52 | 显示全部楼层
第一次的实践咱们干点无聊的事,argc的值默认是多少?如果我不输入任何参数会执行usage函数吗?那我们就简单编写一部分代码,上传的Linux服务器编译测试一下。
  1. #include <stdio.h>
  2. ……………………………………….
  3. int main(int argc, char *argv[])
  4. {
  5.    if(argc == 1)
  6.    {
  7.       usage();
  8.         return 2;
  9.    }
  10.     return 0;
  11. }


 楼主| stm32jy 发表于 2021-1-7 21:55 | 显示全部楼层
可以看到在不输入任何参数情况下打印了一些提示字符串,证明argc默认的值是为1,如果在a.out 后面输入一个参数,此时argc为2,不会执行打印,将fprintf换成printf一样可以正常打印,这里我就不纠结使用哪个了哈!
594245ff7125899e0d.png
 楼主| 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,其它格式错误
 楼主| stm32jy 发表于 2021-1-7 21:56 | 显示全部楼层
主函数切割短片2
  1. while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF )
  2. {
  3. switch(opt)
  4.      {
  5.           case  0 : break;
  6.           case 'f': force=1;break;
  7.           case 'r': force_reload=1;break;
  8.           case '9': http10=0;break;
  9.           case '1': http10=1;break;
  10.           case '2': http10=2;break;
  11.           case 'V': printf(PROGRAM_VERSION"\n");exit(0);
  12.           case 't': benchtime=atoi(optarg);break;
  13.           case 'p':
  14.                 /* proxy server parsing server:port */
  15.                 tmp=strrchr(optarg,':');
  16.                 proxyhost=optarg;
  17.                 if(tmp==NULL)
  18.                 {
  19.                     break;
  20.                 }
  21.                 if(tmp==optarg)
  22.                 {
  23.                     fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg);
  24.                     return 2;
  25.                 }
  26.                 if(tmp==optarg+strlen(optarg)-1)
  27.                 {
  28.                    fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg);
  29.                     return 2;
  30.                 }
  31.                 *tmp='\0';
  32.                 proxyport=atoi(tmp+1);break;
  33.           case ':':
  34.           case 'h':
  35.           case '?': usage();return 2;break;
  36.           case 'c': clients=atoi(optarg);break;
  37.      }
  38. }

 楼主| stm32jy 发表于 2021-1-7 21:59 | 显示全部楼层
为了更好的理解,先简单使用getopt函数写一个伪指令代码测试一下,测试选项中912Vfr?h字符选项都不带参数,tpc字符选项需要加参数输入。
  1. int main(int argc, char *argv[])
  2. {
  3.    int opt = 0;
  4.    if(argc == 1)
  5.    {
  6.       usage();
  7.         return 2;
  8.    }
  9.    while((opt=getopt(argc,argv,"912Vfrt:p:c:?h"))!=-1 )
  10.     {
  11.      switch(opt)
  12.      {
  13.           case  0 : break;
  14.           case 'f': printf("f\n");break;
  15.           case 'r': printf("r\n");break;
  16.           case '9': printf("9\n");break;
  17.           case '1': printf("1\n");break;
  18.           case '2': printf("2\n");break;
  19.           case 'V': printf("V\n");break;
  20.           case 't': printf("t\n");break;
  21.           case 'p': printf("p\n");break;
  22.           case 'h': printf("h\n");break;
  23.           case '?': printf("?\n");break;
  24.           case 'c': printf("c\n");break;
  25.      }
  26.     }
  27.     return 0;
  28. }


 楼主| stm32jy 发表于 2021-1-7 22:02 | 显示全部楼层
测试结果可以看到,输入-f 可以得到正确的的打印,输入 –t 时由于没有加参数,会提示且打印参数错误。
271705ff713e6ea309.png
 楼主| 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);
 楼主| 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的值 */
};
 楼主| stm32jy 发表于 2021-1-7 22:11 | 显示全部楼层
接着使用option结构体定义了long_options结构体数组,具体内容如下:
  1. #define METHOD_GET 0
  2. #define METHOD_HEAD 1
  3. #define METHOD_OPTIONS 2
  4. #define METHOD_TRACE 3

  5. int method=METHOD_GET;
  6. int force=0;
  7. int force_reload=0;

  8. static const struct option long_options[]=
  9. {
  10. {"force",no_argument,&force,1},
  11. {"reload",no_argument,&force_reload,1},
  12. {"time",required_argument,NULL,'t'},
  13. {"help",no_argument,NULL,'?'},
  14. {"http09",no_argument,NULL,'9'},
  15. {"http10",no_argument,NULL,'1'},
  16. {"http11",no_argument,NULL,'2'},
  17. {"get",no_argument,&method,METHOD_GET},
  18. {"head",no_argument,&method,METHOD_HEAD},
  19. {"options",no_argument,&method,METHOD_OPTIONS},
  20. {"trace",no_argument,&method,METHOD_TRACE},
  21. {"version",no_argument,NULL,'V'},
  22. {"proxy",required_argument,NULL,'p'},
  23. {"clients",required_argument,NULL,'c'},
  24. {NULL,0,NULL,0}
  25. };


 楼主| stm32jy 发表于 2021-1-7 22:12 | 显示全部楼层
getopt_long函数测试
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <getopt.h>

  4. #define METHOD_GET 0
  5. #define METHOD_HEAD 1
  6. #define METHOD_OPTIONS 2
  7. #define METHOD_TRACE 3

  8. int method=METHOD_GET;
  9. int force=0;
  10. int force_reload=0;

  11. static const struct option long_options[]=
  12. {
  13. {"force",no_argument,&force,1},
  14. {"reload",no_argument,&force_reload,1},
  15. {"time",required_argument,NULL,'t'},
  16. {"help",no_argument,NULL,'?'},
  17. {"http09",no_argument,NULL,'9'},
  18. {"http10",no_argument,NULL,'1'},
  19. {"http11",no_argument,NULL,'2'},
  20. {"get",no_argument,&method,METHOD_GET},
  21. {"head",no_argument,&method,METHOD_HEAD},
  22. {"options",no_argument,&method,METHOD_OPTIONS},
  23. {"trace",no_argument,&method,METHOD_TRACE},
  24. {"version",no_argument,NULL,'V'},
  25. {"proxy",required_argument,NULL,'p'},
  26. {"clients",required_argument,NULL,'c'},
  27. {NULL,0,NULL,0}
  28. };
  29. void usage()
  30. {
  31.     printf(
  32.         "webbench [option]... URL\n"
  33.         "  -f|--force               Don't wait for reply from server.\n"
  34.         "  -r|--reload              Send reload request - Pragma: no-cache.\n"
  35.         "  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.\n"
  36.         "  -p|--proxy <server:port> Use proxy server for request.\n"
  37.         "  -c|--clients <n>         Run <n> HTTP clients at once. Default one.\n"
  38.         "  -9|--http09              Use HTTP/0.9 style requests.\n"
  39.         "  -1|--http10              Use HTTP/1.0 protocol.\n"
  40.         "  -2|--http11              Use HTTP/1.1 protocol.\n"
  41.         "  --get                    Use GET request method.\n"
  42.         "  --head                   Use HEAD request method.\n"
  43.         "  --options                Use OPTIONS request method.\n"
  44.         "  --trace                  Use TRACE request method.\n"
  45.         "  -?|-h|--help             This information.\n"
  46.         "  -V|--version             Display program version.\n"
  47.         );

  48. }
  49. int main(int argc, char *argv[])
  50. {
  51.    int opt = 0;
  52.    int longindex = 0;
  53.    if(argc == 1)
  54.    {
  55.       usage();
  56.         return 2;
  57.    }
  58.    while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&longindex))!=-1 )
  59.     {
  60.      switch(opt)
  61.      {
  62.           case  0 : break;
  63.           case 'f': printf("f\n");break;
  64.           case 'r': printf("r\n");break;
  65.           case '9': printf("9\n");break;
  66.           case '1': printf("1\n");break;
  67.           case '2': printf("2\n");break;
  68.           case 'V': printf("V\n");exit(0);
  69.           case 't': printf("t\n");break;
  70.           case 'p': printf("p\n");break;
  71.           case ':': printf(":\n");break;
  72.           case 'h': printf("h\n");break;
  73.           case '?': usage();break;
  74.           case 'c': printf("c\n");break;
  75.      }
  76.     }
  77.     return 0;
  78. }


 楼主| stm32jy 发表于 2021-1-7 22:15 | 显示全部楼层
测试结果如下
896045ff716de62988.png
xiaoqizi 发表于 2021-2-3 20:46 | 显示全部楼层
什么机构的视频教学啊
木木guainv 发表于 2021-2-3 20:48 | 显示全部楼层
非常感谢楼主分享的资料
磨砂 发表于 2021-2-3 20:49 | 显示全部楼层
可以用来对stm干嘛啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

1118

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部
0