webbench简介
网站压力测试,有四种方式GET,HEAD,OPTIONS,TRACE,通过多进程时间,可通过自由调整参数改变并发数量
int method --head 发送http报文的方式
int clients --子进程的个数,也就是并发的个数
int force -f 是否读取服务器返回的数据,默认0--读取,
int force_reload -r 缓存
int proxyport 端口
char *proxyhost ip地址
char *req_url url链接地址/*"http://www.baidu.com/"*/
新遇到的函数
strncasecmp
忽略大小写比对字符串
#include <strings.h>
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
index
查找字符串中第一个出现的指定字符的地址
#include <strings.h>
char *index(const char *s, int c);
char *rindex(const char *s, int c);
setvbuf
设置文件流的缓冲区
int setvbuf(FILE *stream , char *buf , int mode, size_t size);
gethostbyname
通过域名"www.baidu.com"得到IP地址,但是已经淘汰
#include <netdb.h>
extern int h_errno;
struct hostent *gethostbyname(const char *name);
struct hostent {
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
}
hp = gethostbyname(host);
memcpy (&ad.sin_addr, hp->h_addr, hp->h_length);
printf ("ip is %s, %d\n" , inet_ntop(AF_INET, &ad.sin_addr, buf, sizeof (buf)), clientPort);
整理后的源代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h>
#include <rpc/types.h>
#include <getopt.h>
#include <strings.h>
#include <time.h>
#include <signal.h>
#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 <stdarg.h>
#define PROGRAM_VERSION "1.5" /* 版本号 */
volatile int timerexpired = 0 ;
int speed = 0 ;
int failed = 0 ;
int bytes = 0 ;
int http10 = 1 ;
#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 ;
char *proxyhost = NULL;
char *req_url = NULL;
int benchtime = 30 ;
int mypipe[2 ];
char host[MAXHOSTNAMELEN];
#define REQUEST_SIZE 2048
char request[REQUEST_SIZE];
static void dealarg(int , char **);
static void benchcore(const char *host, const int port, const char *request);
static int bench(void );
static void build_request(const char *url);
static void alarm_handler(int signal)
{
timerexpired = 1 ;
}
static void usage(void )
{
fprintf (stderr,
"webbench [option]... URL<\"http://www.baidu.com/\">\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_ip: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[])
{
if (argc == 1 ) {
usage();
return 2 ;
}
dealarg(argc, argv);
#if 0
printf ("http10 is %d\nmethod is %d\nclients is %d\n"
"force is %d\nforce_reload is %d\n"
"proxyport is %d\nproxyhost is %s\n" , http10, method, clients,\
force, force_reload, proxyport, proxyhost);
#endif
fprintf (stderr,
"Webbench - Simple Web Benchmark " PROGRAM_VERSION"\n"
"Copyright (c) Radim Kolar 1997-2004, GPL Open Source software.\n" );
build_request(req_url);
printf ("url is %s\n" , req_url);
printf ("\nBenchmarking: " );
switch (method) {
case METHOD_GET:
default :
printf ("GET" );
break ;
case METHOD_OPTIONS:
printf ("OPTIONS" );
break ;
case METHOD_HEAD:
printf ("HEAD" );
break ;
case METHOD_TRACE:
printf ("TRACE" );
break ;
}
printf (" %s" , req_url);
switch (http10) {
case 0 :
printf (" (using HTTP/0.9)" );
break ;
case 1 :
printf (" (using HTTP/1.0)" );
break ;
case 2 :
printf (" (using HTTP/1.1)" );
break ;
}
printf ("\n" );
if (clients == 1 ) {
printf ("1 client" );
} else {
printf ("%d clients" , clients);
}
printf (", running %d sec" , benchtime);
if (force) {
printf (", early socket close" );
}
if (proxyhost != NULL) {
printf (", via proxy server %s:%d" , proxyhost, proxyport);
}
if (force_reload) {
printf (", forcing reload" );
}
printf (".\n" );
return bench();
}
void build_request(const char *url)
{
char tmp[10 ];
int i;
bzero(host, MAXHOSTNAMELEN);
bzero(request, REQUEST_SIZE);
if (force_reload && proxyhost != NULL && http10 < 1 ) {
http10 = 1 ;
}
if (method == METHOD_HEAD && http10 < 1 ) {
http10 = 1 ;
}
if (method == METHOD_OPTIONS && http10 < 2 ) {
http10 = 2 ;
}
if (method == METHOD_TRACE && http10 < 2 ) {
http10 = 2 ;
}
switch (method) {
case METHOD_GET:
default :
strcpy (request, "GET" );
break ;
case METHOD_OPTIONS:
strcpy (request, "OPTIONS" );
break ;
case METHOD_HEAD:
strcpy (request, "HEAD" );
break ;
case METHOD_TRACE:
strcpy (request, "TRACE" );
break ;
}
strcat (request, " " );
if (NULL == strstr (url, "://" )) {
fprintf (stderr, "\n%s: is not a vaild URL.\n" , url);
exit (2 );
}
if (strlen (url) > 1500 ) {
fprintf (stderr, "URL is too long.\n" );
exit (2 );
}
if (proxyhost == NULL) {
if (0 != strncasecmp("http://" , url, 7 )) {
fprintf (stderr, "\nOnly HTTP protocol is directly supported, set --proxy for others.\n" );
exit (2 );
}
}
i = strstr (url, "://" ) - url + 3 ;
if (strchr (url+i, '/' ) == NULL) {
fprintf (stderr, "\nInvalid URL syntax - hostname don't ends with '/'.\n" );
exit (2 );
}
if (proxyhost == NULL) {
if (index(url+i, ':' ) != NULL && index(url+i, ':' ) < index(url+i, '/' )) {
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, "/" ));
}
strcat (request+strlen (request), url+i+strcspn (url+i, "/" ));
} else {
strcat (request, url);
}
if (http10 == 1 ) {
strcat (request, " HTTP/1.0" );
} else if (http10 == 2 ) {
strcat (request, " HTTP/1.1" );
}
strcat (request, "\r\n" );
if (http10 > 0 ) {
strcat (request, "User-Agent: WebBench " PROGRAM_VERSION"\r\n" );
}
if (proxyhost == NULL && http10 > 0 ) {
strcat (request, "Host: " );
strcat (request, host);
strcat (request, "\r\n" );
}
if (force_reload && proxyhost != NULL) {
strcat (request, "Pragma: no-cache\r\n" );
}
if (http10 > 1 ) {
strcat (request, "Connection: close\r\n" );
}
if (http10 > 0 ) {
strcat (request, "\r\n" );
}
printf ("Req:(%s)\n" , request);
}
int bench(void )
{
int i, j, k;
pid_t pid = 0 ;
FILE *f;
i = Socket(proxyhost == NULL ? host : proxyhost, proxyport);
if (i < 0 ) {
fprintf (stderr, "\nConnect to server failed. Aborting benchmark\n" );
return 1 ;
}
printf ("i = %d\n" , i);
close(i);
if (pipe(mypipe)) {
perror("pipe failed." );
return 3 ;
}
for (i = 0 ; i < clients; i++) {
pid = fork();
if (pid <= (pid_t)0 ) {
sleep(1 );
break ;
}
}
if (pid < (pid_t)0 ) {
fprintf (stderr, "problems forking worker no.%d\n" , i);
perror("fork faild." );
return 3 ;
}
if (pid == (pid_t)0 ) {
if (proxyhost == NULL) {
benchcore(host, proxyport, request);
} else {
benchcore(proxyhost, proxyport, request);
}
f = fdopen(mypipe[1 ], "w" );
if (f == NULL) {
perror("open pipe for writing failed." );
return 3 ;
}
fprintf (f, "%d %d %d\n" , speed, failed, bytes);
fclose(f);
return 0 ;
} else {
printf ("parent %d\n" , getpid());
f = fdopen(mypipe[0 ], "r" );
if (f == NULL) {
perror("open pipe for reading failed." );
return 3 ;
}
setvbuf(f, NULL, _IONBF, 0 );
speed = 0 ;
failed = 0 ;
bytes = 0 ;
while (1 ) {
pid = fscanf (f, "%d %d %d" , &i, &j, &k);
if (pid < 2 ) {
fprintf (stderr, "Some of our childrens died.\n" );
break ;
}
speed += i;
failed += j;
bytes += k;
if (--clients == 0 ) {
wait(NULL);
break ;
}
}
fclose(f);
printf ("\nSpeed=%d pages/min, %d bytes/sec.\nRequests: %d susceed, %d failed.\n" ,
(int )((speed+failed)/(benchtime/60.0f )),
(int )(bytes/(float )benchtime),
speed, failed);
}
return i;
}
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 ) {
if (timerexpired) {
if (failed > 0 ) {
failed--;
}
return ;
}
s = Socket(host, port);
if (s < 0 ) {
failed++;
continue ;
}
if (http10 == 0 ) {
if (shutdown(s, SHUT_WR)) {
failed++;
close(s);
continue ;
}
}
if (force == 0 ) {
while (1 ) {
if (timerexpired) {
break ;
}
i = read(s, buf, 1500 );
if (i < 0 ) {
failed++;
close(s);
goto nexttry;
} else {
if (i == 0 ) {
break ;
} else {
bytes += 1 ;
}
}
}
}
if (close(s)) {
failed++;
continue ;
}
speed++;
}
}
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 dealarg(int argc, char **argv)
{
int opt = 0 ;
int options_index = 0 ;
char *tmp = NULL;
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' :
tmp = strrchr (optarg, ':' );
proxyhost = strdup(optarg);
if (tmp == NULL) {
break ;
}
if (tmp == optarg) {
fprintf (stderr, "Error in option --proxy %s: Missing hostname.\n" , optarg);
exit (2 );
}
if (tmp == optarg + strlen (optarg) - 1 ) {
fprintf (stderr, "Error in option --proxy %s Port number is missing.\n" , optarg);
exit (2 );
}
*tmp = '\0' ;
proxyport = atoi(tmp+1 );
break ;
case ':' :
case 'h' :
case '?' :
usage();
exit (2 );
case 'c' :
clients = atoi(optarg);
break ;
}
}
if (optind == argc) {
fprintf (stderr, "webbench:Missing URL!\n" );
fprintf (stderr, "---------------------------\n" );
usage();
exit (2 );
}
req_url = strdup(argv[optind]);
if (clients == 0 ) {
clients = 1 ;
}
if (benchtime == 0 ) {
benchtime = 60 ;
}
}
int Socket(const char *host, int clientPort)
{
int sock;
unsigned long inaddr;
struct sockaddr_in ad;
struct hostent *hp;
char buf[1024 ];
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 {
hp = gethostbyname(host);
if (hp == NULL)
return -1 ;
memcpy (&ad.sin_addr, hp->h_addr, hp->h_length);
}
ad.sin_port = htons(clientPort);
printf ("ip is %s, %d\n" , inet_ntop(AF_INET, &ad.sin_addr, buf, sizeof (buf)), 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;
}