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