webbench 下载_webbench 压力测试软件

#include"Socket.h"

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

static void usage(void)

{

fprintf(stderr,

"webbench [选项参数]... URL\n"

"  -f|--force              不等待服务器响应\n"

"  -r|--reload              重新请求加载(无缓存)\n"

"  -t|--time           运行时间,单位:秒,默认为30秒\n"

"  -p|--proxy 使用代理服务器发送请求\n"

"  -c|--clients         创建多少个客户端,默认为1个\n"

"  -9|--http09              使用http0.9协议来构造请求\n"

"  -1|--http10              使用http1.0协议来构造请求\n"

"  -2|--http11              使用http1.1协议来构造请求\n"

"  --get                    使用GET请求方法\n"

"  --head                  使用HEAD请求方法\n"

"  --options                使用OPTIONS请求方法\n"

"  --trace                  使用TRACE请求方法\n"

"  -?|-h|--help            显示帮助信息\n"

"  -V|--version            显示版本信息\n"  );

};

//http请求方法

#define METHOD_GET 0

#define METHOD_HEAD 1

#define METHOD_OPTIONS 2

#define METHOD_TRACE 3

//相关参数选项的默认值

int method = METHOD_GET;

int clients = 1;

int force = 0;          //默认需要等待服务器相应

int force_reload = 0;    //默认不重新发送请求

int proxyport = 80;    //默认访问80端口,http国际惯例

char* proxyhost = NULL; //默认无代理服务器,因此初值为空

int benchtime = 30;    //默认模拟请求时间

//所用协议版本

int http = 1;  //0:http0.9 1:http1.0 2:http1.1

//用于父子进程通信的管道

int mypipe[2];

//存放目标服务器的网络地址

char host[MAXHOSTNAMELEN];

//存放请求报文的字节流

#define REQUEST_SIZE 2048

char request[REQUEST_SIZE];

//构造长选项与短选项的对应

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}

};

int speed = 0;

int failed = 0;

long long bytes = 0;

int timeout = 0;

void build_request(const char* url);

static int bench();

static void alarm_handler(int signal);

void benchcore(const char* host,const int port,const char* req);

int main(int argc,char* argv[])

{

int opt = 0;

int options_index = 0;

char* tmp = NULL;

//首先进行命令行参数的处理

//1.没有输入选项

if(argc == 1)

{

usage();

return 1;

}

//2.有输入选项则一个一个解析

while((opt = getopt_long(argc,argv,"frt:p:c:?V912",long_options,&options_index)) != EOF)

{

switch(opt)

{

case 'f':

force = 1;

break;

case 'r':

force_reload = 1;

break;

case '9':

http = 0;

break;

case '1':

http = 1;

break;

case '2':

http = 2;

break;

case 'V':

printf("WebBench 1.5 covered by fh\n");

exit(0);

case 't':

benchtime = atoi(optarg);  //optarg指向选项后的参数

break;

case 'c':

clients = atoi(optarg);    //与上同

break;

case 'p':  //使用代理服务器,则设置其代理网络号和端口号,格式:-p server:port

tmp = strrchr(optarg,':'); //查找':'在optarg中最后出现的位置

proxyhost = optarg;        //

if(tmp == NULL)    //说明没有端口号

{

break;

}

if(tmp == optarg)  //端口号在optarg最开头,说明缺失主机名

{

fprintf(stderr,"选项参数错误,代理服务器 %s:缺失主机名",optarg);

return 2;

}

if(tmp == optarg + strlen(optarg)-1)    //':'在optarg末位,说明缺少端口号

{

fprintf(stderr,"选项参数错我,代理服务器 %s 缺少端口号",optarg);

return 2;

}

*tmp = '\0';      //将optarg从':'开始截断

proxyport = atoi(tmp+1);    //把代理服务器端口号设置好

break;

case '?':

usage();

exit(0);

break;

default:

usage();

return 2;

break;

}

}

//选项参数解析完毕后,刚好是读到URL,此时argv[optind]指向URL

if(optind == argc)    //这样说明没有输入URL,不明白的话自己写一条命令行看看

{

fprintf(stderr,"缺少URL参数\n");

usage();

return 2;

}

if(benchtime == 0)

benchtime = 30;

fprintf(stderr,"webbench: 一款轻巧的网站测压工具 1.5 covered by fh\nGPL Open Source Software\n");

//OK,我们解析完命令行后,首先先构造http请求报文

build_request(argv[optind]);    //参数当然是URL

//请求报文构造好了

//开始测压

printf("\n测试中:\n");

switch(method)

{

case METHOD_OPTIONS:

printf("OPTIONS");

break;

case METHOD_HEAD:

printf("HEAD");

break;

case METHOD_TRACE:

printf("TRACE");

break;

case METHOD_GET:

default:

printf("GET");

break;

}

printf(" %s",argv[optind]);

switch(http)

{

case 0:

printf("(使用 HTTP/0.9)");

break;

case 1:

printf("(使用 HTTP/1.0)");

break;

case 2:

printf("(使用 HTTP/1.1)");

break;

}

printf("\n");

printf("%d 个客户端",clients);

printf(",%d s",benchtime);

if(force)

printf(",选择提前关闭连接");

if(proxyhost != NULL)

printf(",经由代理服务器 %s:%d  ",proxyhost,proxyport);

if(force_reload)

printf(",选择无缓存");

printf("\n");  //换行不能少!库函数是默认行缓冲,子进程会复制整个缓冲区,

//若不换行刷新缓冲区,子进程会把缓冲区的的也打出来!

//而换行后缓冲区就刷新了,子进程的标准库函数的那块缓冲区就不会有前面的这些了

//真正开始压力测试

return bench();

}

void build_request(const char* url)

{

char tmp[10];

int i = 0;

bzero(host,MAXHOSTNAMELEN);

bzero(request,REQUEST_SIZE);

//缓存和代理都是http1.0后才有的

//无缓存和代理都要在http1.0以上才能使用

//因此这里要处理一下,不然可能会出问题

if(force_reload && proxyhost != NULL && http < 1)

http = 1;

//HEAD请求是http1.0后才有

if(method == METHOD_HEAD && http < 1)

http = 1;

//OPTIONS和TRACE都是http1.1才有

if(method == METHOD_OPTIONS && http < 2)

http = 2;

if(method == METHOD_TRACE && http < 2)

http = 2;

//开始填写http请求

//请求行

//填写请求方法

switch(method)

{

case METHOD_HEAD:

strcpy(request,"HEAD");

break;

case METHOD_OPTIONS:

strcpy(request,"OPTIONS");

break;

case METHOD_TRACE:

strcpy(request,"TRACE");

break;

default:

case METHOD_GET:

strcpy(request,"GET");

}

strcat(request," ");

//判断URL的合法性

//1.URL中没有"://"

if(strstr(url,"://") == NULL)

{

fprintf(stderr,"\n%s:是一个不合法的URL\n",url);

exit(2);

}

//2.URL过长

if(strlen(url) > 1500)

{

fprintf(stderr,"URL 长度过过长\n");

exit(2);

}

//3.没有代理服务器却填写错误

if(proxyhost == NULL)  //若无代理

{

if(strncasecmp("http://",url,7) != 0)  //忽略大小写比较前7位

{

fprintf(stderr,"\nurl无法解析,是否需要但没有选择使用代理服务器的选项?\n");

usage();

exit(2);

}

}

//定位url中主机名开始的位置

//比如  http://www.xxx.com/

i = strstr(url,"://") - url + 3;

//4.在主机名开始的位置找是否有'/',若没有则非法

if(strchr(url + i,'/') == NULL)

{

fprintf(stderr,"\nURL非法:主机名没有以'/'结尾\n");

exit(2);

}

//判断完URL合法性后继续填写URL到请求行

//无代理时

if(proxyhost == NULL)

{

//有端口号时,填写端口号

if(index(url+i,':') != NULL && index(url,':') < index(url,'/'))

{

//设置域名或IP

strncpy(host,url+i,strchr(url+i,':') - url - i);

bzero(tmp,10);

strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/') - index(url+i,':')-1);

//设置端口号

proxyport = atoi(tmp);

//避免写了':'却没写端口号

if(proxyport == 0)

proxyport = 80;

}

else    //无端口号

{

strncpy(host,url+i,strcspn(url+i,"/"));  //找到url+i到第一个”/"之间的字符个数

}

}

else    //有代理服务器就简单了,直接填就行,不用自己处理

{

strcat(request,url);

}

//填写http协议版本到请求行

if(http == 1)

strcat(request," HTTP/1.0");

if(http == 2)

strcat(request," HTTP/1.1");

strcat(request,"\r\n");

//请求报头

if(http > 0)

strcat(request,"User-Agent:WebBench 1.5\r\n");

//填写域名或IP

if(proxyhost == NULL && http > 0)

{

strcat(request,"Host: ");

strcat(request,host);

strcat(request,"\r\n");

}

//若选择强制重新加载,则填写无缓存

if(force_reload && proxyhost != NULL)

{

strcat(request,"Pragma: no-cache\r\n");

}

//我们目的是构造请求给网站,不需要传输任何内容,当然不必用长连接

//否则太多的连接维护会造成太大的消耗,大大降低可构造的请求数与客户端数

//http1.1后是默认keep-alive的

if(http > 1)

strcat(request,"Connection: close\r\n");

//填入空行后就构造完成了

if(http > 0)

strcat(request,"\r\n");

}

//父进程的作用:创建子进程,读子进程测试到的数据,然后处理

static int bench()

{

int i = 0,j = 0;

long long k = 0;

pid_t pid = 0;

FILE* f = NULL;

//尝试建立连接一次

i = Socket(proxyhost == NULL?host:proxyhost,proxyport);

if(i < 0)

{

fprintf(stderr,"\n连接服务器失败,中断测试\n");

return 3;

}

close(i);//尝试连接成功了,关闭该连接

//建立父子进程通信的管道

if(pipe(mypipe))

{

perror("通信管道建立失败");

return 3;

}

//让子进程去测试,建立多少个子进程进行连接由参数clients决定

for(i = 0;i < clients;i++)

{

pid = fork();

if(pid <= 0)

{

sleep(1);

break;  //失败或者子进程都结束循环,否则该子进程可能继续fork了,显然不可以

}

}

//处理fork失败的情况

if(pid < 0)

{

fprintf(stderr,"第 %d 子进程创建失败",i);

perror("创建子进程失败");

return 3;

}

//子进程执行流

if(pid == 0)

{

//由子进程来发出请求报文

benchcore(proxyhost == NULL?host : proxyhost,proxyport,request);

//子进程获得管道写端的文件指针

f = fdopen(mypipe[1],"w");

if(f == NULL)

{

perror("管道写端打开失败");

return 3;

}

//向管道中写入该子进程在一定时间内请求成功的次数

//失败的次数

//读取到的服务器回复的总字节数

fprintf(f,"%d %d %lld\n",speed,failed,bytes);

fclose(f);  //关闭写端

return 0;

}

else

{

//子进程获得管道读端的文件指针

f = fdopen(mypipe[0],"r");

if(f == NULL)

{

perror("管道读端打开失败");

return 3;

}

//fopen标准IO函数是自带缓冲区的,

//我们的输入数据非常短,并且要求数据要及时,

//因此没有缓冲是最合适的

//我们不需要缓冲区

//因此把缓冲类型设置为_IONBF

setvbuf(f,NULL,_IONBF,0);

speed = 0;  //连接成功的总次数,后面除以时间可以得到速度

failed = 0; //失败的请求数

bytes = 0;  //服务器回复的总字节数

//唯一的父进程不停的读

while(1)

{

pid = fscanf(f,"%d %d %lld",&i,&j,&k);//得到成功读入的参数个数

if(pid < 3)

{

fprintf(stderr,"某个子进程死亡\n");

break;

}

speed += i;

failed += j;

bytes += k;

//我们创建了clients,正常情况下要读clients次

if(--clients == 0)

break;

}

fclose(f);

//统计处理结果

printf("\n速度:%d pages/min,%d bytes/s.\n请求:%d 成功,%d 失败\n",\

(int)((speed+failed)/(benchtime/60.0f)),\

(int)(bytes/(float)benchtime),\

speed,failed);

}

return i;

}

//闹钟信号处理函数

static void alarm_handler(int signal)

{

timeout = 1;

}

//子进程真正的向服务器发出请求报文并以其得到此期间的相关数据

void benchcore(const char* host,const int port,const char* req)

{

int rlen;

char buf[1500];

int s,i;

struct sigaction sa;

//安装闹钟信号的处理函数

sa.sa_handler = alarm_handler;

sa.sa_flags = 0;

if(sigaction(SIGALRM,&sa,NULL))

exit(3);

//设置闹钟函数

alarm(benchtime);

rlen = strlen(req);

nexttry:

while(1)

{

//只有在收到闹钟信号后会使 time = 1

//即该子进程的工作结束了

if(timeout)

{

if(failed > 0)

{

failed--;

}

return;

}

//建立到目标网站服务器的tcp连接,发送http请求

s = Socket(host,port);

if(s < 0)

{

failed++;  //连接失败

continue;

}

//发送请求报文

if(rlen != write(s,req,rlen))

{

failed++;

close(s);  //写失败了也不能忘了关闭套接字

continue;

}

//http0.9的特殊处理

//因为http0.9是在服务器回复后自动断开连接的,不keep-alive

//在此可以提前先彻底关闭套接字的写的一半,如果失败了那么肯定是个不正常的状态,

//如果关闭成功则继续往后,因为可能还有需要接收服务器的恢复内容

//但是写这一半是一定可以关闭了,作为客户端进程上不需要再写了

//因此我们主动破坏套接字的写端,但是这不是关闭套接字,关闭还是得close

//事实上,关闭写端后,服务器没写完的数据也不会再写了,这个就不考虑了

if(http == 0)

{

if(shutdown(s,1))

{

failed++;

close(s);

continue;

}

}

//-f没有设置时默认等待服务器的回复

if(force == 0)

{

while(1)

{

if(timeout)

break;

i = read(s,buf,1500);  //读服务器发回的数据到buf中

if(i < 0)

{

failed++;  //读失败

close(s);  //失败后一定要关闭套接字,不然失败个数多时会严重浪费资源

goto nexttry;  //这次失败了那么继续下一次连接,与发出请求

}

else

{

if(i == 0)  //读完了

break;

else

bytes += i; //统计服务器回复的字节数

}

}

}

if(close(s))

{

failed++;

continue;

}

speed++;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Webench是一款功能非常强大的在线设计和仿真工具,可以对电源、LED、放大器、滤波器、音频、接口、等进行仿真与设计,因为Webench巨大的便捷快速性和强大的设计仿真功能,让我一接触到这款软件,就深深的被它吸引了,为我的工作带来了极大的方便,提高了我的工作效率,大大缩短了我们开发电源芯片的时间,其优越的仿真功能也让我们减少了开发的成本,今天我们就利用webench强大的电源设计软件设计一款车载充电转换器。 1.点击注册/登录MYTI :点击注册MYTI(注:首先要先注册Ti的官方账户,并成功登陆,否则无法正常使用在线的WEBENCH设计软件) 2.点击上图红圈中的“开始设计”按钮:点击开始设计 跳转到如下界面: 3.设计软件加载完插件后会自动进入电源设计界面,系统默认为系统语言为英语,可以自行单击软件菜单栏的“简体中文”,软件则会变为中文(不是所有的界面都汉化了,只是一小部分),如图: 单击后,变为“中文简体”界面, 4.输入相关的设计参数,我们此次设计参数为:输入电压12~24VDC,输出5VDC,输出电流2A,工作温度为室温30度。具体如下图(左)所示,如果想要4.更多的参数设计,可以勾选“Use Advanced Options”选项框,进入如下图(右)所示的界面,我们可以看到在这里可以设定更为详细的参数设置,可以根据自己的偏好和应用要求选择相应的参数需求,单击“OK”可以回到设计界面: 5.单击“显示推荐的电源管理电路”按钮,系统会跳出“Select your power supply solution”(选择你的电源解决方案)对话框,有三种可以选择,根据自己的需求,选择相应的解决方案,在这里我选择了“Integrated”方案,如图; 6.单击上图中Integrated中的“choose part ”按钮,系统自动生成多个符合要求的设计方案,如图共生成159个设计方案,这些方案中我们可以根据我们设计要求的侧重点进行排序,比如我们主要考虑“效率(%)”因素,可以点击红框内的“效率(%)”按钮,这些设计方案就会按照效率的高低自动进行排序,另外也可以根据“BOM成本”以及“BOM覆盖面积”进行筛选: 7.另外我们可以根据软件界面的右上角的“Webench 优化工具”,可以更加直观的综合考虑“BOM覆盖面积”、“BOM成本”以及“效率”三者之间的取舍,直接拖动箭头,就可以任意的调整,然后会生成最新的设计方案; 8.根据自己的需要,选择一个合理的方案,在这里我们选择TPS54332为例进行设计,点击“开启设计”进去,就可以看到完整的设计资料: 可以看到软件给出的设计资料非常的全面,具体包括: (a) 参数曲线图, (b) 电路原理图, (c) 热仿真图, (d) 工作运行值, (e) BOM表; (f) 相关的输出下载选项。 单击相应的选项可以查看到更多的设计细节。 9.输出相关的设计文件资料,在右图中可以看到主要有如下几个输出选项: ① PDF设计文档输出 ② CAD文件输出 ③ SIM文件输出 大家可以根据自己的需要,点击相应的选项,进行输出。 到这里,一个符合要求的电源设计方案就完成了,大家可以看到Ti Webench 电源设计软件还是非常方便快捷的,基本可以一步到位,大家可以自己动手尝试一下。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值