Web bench源码剖析

一、Web bench是什么?

首先提一个概念—-压力测试
在运维工作中,压力测试是一项很重要的工作。比如在一个网站上线之前,能承受多大访问量、在大访问量情况下性能怎样,这些数据指标好坏将会直接影响用户体验。但是,在压力测试中存在一个共性,那就是压力测试的结果与实际负载结果不会完全相同,就算压力测试工作做的再好,也不能保证100%和线上性能指标相同。面对这些问题,我们只能尽量去想方设法去模拟。所以,压力测试非常有必要,有了这些数据,我们就能对自己做维护的平台做到心中有数。

Web bench — 简洁而优美的压力测试工具
为什么这么说呢?
Web Bench是一个网站压力测试的工具。其最后更新时间是2004年,已经十年多了。其源代码总共才500多行,全部使用C语言编写,最多可以模拟3万个并发连接,真可谓是简洁代码的代表之作。

二、实现原理

同它的实现代码一样,Webbench的代码实现原理也是相当简单,就是一个父进程fork出很多个子进程,子进程分别去执行http测试,最后把执行结果汇总写入管道,父进程读取管道数据然后进行最终测试结果的计算。

整个工具的实现流程:
这里写图片描述

三、源码剖析

1、源码下载地址:WebBench源码下载地址
下载方法:在linux指定目录的命令行中输入:

git clone https://github.com/EZLippi/WebBench.git

等下载完成之后源码文件夹即在指定目录。

2、源代码的组成::socket.c webbench.c
socket.c是创建socket连接的。主要的功能代码在webbench.c中。

Socket函数的大致内容如下:

int Socket(const char *host, int clientPort)
{
    //以host为服务器端ip,clientPort为服务器端口号建立socket连接
    //连接类型为TCP,使用IPv4网域
    //一旦出错,返回-1
    //正常连接,则返回socket描述符
}

socket.c源代码及注释:

[cpp] 
/* $Id: socket.c 1.1 1995/01/01 07:11:14 cthuang Exp $ 
 * 
 * This module has been modified by Radim Kolar for OS/2 emx 
 */ 

/********************************************************\
  module:       socket.c 
  program:      popclient 
  SCCS ID:      @(#)socket.c    1.5  4/1/94 
  programmer:   Virginia Tech Computing Center 
  compiler:     DEC RISC C compiler (Ultrix 4.1) 
  environment:  DEC Ultrix 4.3  
  description:  UNIX sockets code. 
 ********************************************************/ 
  #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>

  /****************************************
   * 功能:通过ip地址和端口号建立网路连接
   * @host:网络ip地址
   * @clientport:端口号
   * return:建立的socket连接,如果返回-1,则表示建立连接失败
   *****************************************/
  int Socket(const char *host, int clientport)
  {
      int sock;
      unsigned long inaddr;
      struct sockaddr_in ad;
      struct hostent *hp;

      memset(&ad, 0, sizeof(ad));//初始化地址
      ad.sin_family = AF_INET;

      inaddr = inet_addr(host);//将点分十进制的主机序列转换成无符号的长整形的网络序列
      if (inaddr != INADDR_NONE)
          memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
      else//如果host是域名
      {
          hp = gethostbyname(host);//用域名获取ip,下面介绍
          if (hp == null)
              return -1;
          memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
      }
      ad.sin_port = htons(clientport);//将端口号从主机序列转为网络序列

      sock = socket(AF_INET, SOCK_STREAM, 0);//创建套接字
      if (sock < 0)
          return sock;
      if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0)//建立网络连接
          return -1;
      return sock;
  }

函数gethostbyname功能:通过域名获取ip地址

#include <netdb.h>
3include<sys/socket.h>
struct hostent *gethostbyname(const char *name);

这个函数的参数是传入值是域名或者主机名,例如”www.google.cn”等等。传出值,是一个hostent的结构。如果函数调用失败,将返回NULL。
返回hostent结构体类型指针:

 struct hostent
    {
        char    *h_name;     //主机的规范名          
        char    **h_aliases; //主机的别名
        int     h_addrtype;  //主机ip地址的类型,主机ip地址的类型,ipv4(AF_INET)或ipv6(AF_INET6)
        int     h_length;   //主机ip地址的长度
        char    **h_addr_list; //主机的ip地址,以网络字节序存储,如果需要打印,需调用inet_ntop()函数,切记不能用printf函数直接打印。
        #define h_addr h_addr_list[0]
    };

inet_ntop函数:

const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) ;

此函数将类型为af的网络地址结构src,转换成主机序的字符串形式,存放在长度为cnt的字符串中。返回指向dst的一个指针。如果函数调用错误,返回值是NULL。

webbebch.c中的主要函数

  • static void usage(void):提示Webbench的用法及命令
  • static void alarm_handler(int signal) :信号处理函数,时钟结束时进行调用
  • void build_request(const char *url):创建http连接请求
  • static int bench(void):创建管道和子进程,调用测试http函数,实现父子进程通信并计算结果
  • void benchcore(const char *host,const int port,const char *req):对http请求进行测试(子进程的具体工作)

webbench.c的主要工作流程:

    1. 解析命令行参数,根据命令行指定参数设定变量,可以认为是初始化配置。
  • 2.根据指定的配置构造 HTTP 请求报文格式。
  • 3.开始执行 bench 函数,先进行一次 socket 连接建立与断开,测试是否可以正常访问。
  • 4.建立管道,派生根据指定进程数派生子进程。
  • 5.每个子进程调用 benchcore 函数,先通过 sigaction 安装信号,用 alarm 设置闹钟函数,到时间后会产生SIGALRM信号,调用信号处理函数使子进程停止。接着不断建立 socket 进行通信,与服务器交互数据,直到收到信号结束访问测试。子进程将访问测试结果写进管道。
  • 6.父进程读取管道数据,汇总子进程信息,收到所有子进程消息后,输出汇总信息,结束。
    流程图:
    这里写图片描述

webbench.c源码注释:

 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;//记录失败的数量(speed代表成功,failed代表失败)
 32 int bytes=0;//记录进程成功读取的字节数
 33 
 34 /* globals */
 35 int http10=1; /* http版本:0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */
 36 
 37 /* Allow: GET, HEAD, OPTIONS, TRACE */
 38 #define METHOD_GET 0
 39 #define METHOD_HEAD 1
 40 #define METHOD_OPTIONS 2
 41 #define METHOD_TRACE 3
 42 #define PROGRAM_VERSION "1.5"
 43 int method=METHOD_GET;//默认请求方法为GET,同时也支持HEAD、OPTIONS、TRACE
 44 int clients=1;//并发数目,默认只有一个进程发请求,通过-c参数设置
 45 int force=0;//是否需要等待读取从服务器返回值的数据,0表示需要读取
 46 int force_reload=0;//是否使用缓存,1表示不缓存,0表示缓存页面
 47 int proxyport=80;//代理服务器的端口
 48 char *proxyhost=NULL;//代理服务器的ip
 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
异步FIFO是一种常见的数字电路设计,用来实现数据在不同时钟域之间的传输。Verilog是一种硬件描述语言,用于设计和模拟数字逻辑电路。下面是一个异步FIFO的Verilog码和相应的测试台代码的示例: Verilog异步FIFO码: ```verilog module AsyncFIFO ( input wire clk_wr, input wire reset, input wire enable, input wire data_in, output wire full, output wire empty, output reg data_out ); parameter WIDTH = 8; // 数据位宽 parameter DEPTH = 16; // FIFO深度 reg [WIDTH-1:0] memory[0:DEPTH-1]; reg [WIDTH-1:0] read_pointer, write_pointer; always @(posedge clk_wr or posedge reset) begin if (reset) begin read_pointer <= 0; write_pointer <= 0; data_out <= 0; end else if (enable) begin if (~full) begin memory[write_pointer] <= data_in; write_pointer <= write_pointer + 1; end if (~empty) begin data_out <= memory[read_pointer]; read_pointer <= read_pointer + 1; end end end assign full = (write_pointer - read_pointer) == DEPTH; assign empty = (write_pointer == read_pointer); endmodule ``` Verilog异步FIFO测试台代码: ```verilog module AsyncFIFOTest; reg clk_wr; reg reset; reg enable; reg data_in; wire full; wire empty; wire data_out; AsyncFIFO dut ( .clk_wr(clk_wr), .reset(reset), .enable(enable), .data_in(data_in), .full(full), .empty(empty), .data_out(data_out) ); initial begin clk_wr = 0; reset = 1; enable = 0; data_in = 0; #2 reset = 0; // 写入测试数据 #2 enable = 1; #2 data_in = 1; #2; #2 data_in = 2; #2; #2 data_in = 3; #2 enable = 0; // 读取测试数据 #2 enable = 1; #2 enable = 0; // 检查输出数据 $display("data_out: %d", data_out); #2; $display("empty: %b", empty); $finish; end always begin #1 clk_wr = ~clk_wr; end endmodule ``` 以上是一个简单的8位宽、16深度的异步FIFO模块和相应的测试台代码。测试台首先初始化FIFO,然后写入数据1、2、3,最后读取数据并检查输出数据和空状态。 这是一个只包含基本功能的示例,实际应用中可能还需要添加写入满和读取空的异常处理等功能。同时,测试台代码也可以根据具体需求进行修改和扩展以进行更全面的测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值