ptester.c
上传用户:ladybrid91
上传日期:2007-01-04
资源大小:287k
文件大小:12k
源码类别:

Web服务器

开发平台:

Unix_Linux

  1. /*
  2. ** ptester.c A HTTP daemon tester program
  3. **
  4. ** Copyright (c) 1995 Peter Eriksson <pen@signum.se>
  5. **
  6. ** This program is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2 of the License, or
  9. ** (at your option) any later version.
  10. **
  11. ** This program is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program; if not, write to the Free Software
  17. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. #include <stdio.h>
  20. #include <signal.h>
  21. #include <stdlib.h>
  22. #include <unistd.h>
  23. #include <errno.h>
  24. #include <string.h>
  25. #include <ctype.h>
  26. #include <netdb.h>
  27. #include <syslog.h>
  28. #include <alloca.h>
  29. #include <thread.h>
  30. #include <sys/types.h>
  31. #include <sys/time.h>
  32. #include <sys/socket.h>
  33. #include <netinet/in.h>
  34. #include <netinet/tcp.h>
  35. #include <arpa/inet.h>
  36. int debug = 0;
  37. int bound_threads = 0;
  38. int repeat = 1;
  39. int expected_bytes = 0;
  40. int concurrency = 0;
  41. char *server_host = "127.0.0.1";
  42. char *server_port = "80";
  43. int rcvbuf_size = 0;
  44. int use_exit = 0;
  45. int keepalive = 0;
  46. int http_0 = 0;
  47. int failure = 0;
  48. struct sockaddr_in server_addr;
  49. int total_nrq = 0;
  50. int total_bytes = 0;
  51. int total_failed = 0;
  52. double min_tx = 0.0;
  53. double max_tx = 0.0;
  54. volatile int stop_flag = 0;
  55. int test_length = 60;
  56. mutex_t result_lock;
  57. void xsleep(int timeout)
  58. {
  59.     /* There is a bug in Solaris 2.4's sleep() which causes
  60.        it to return random garbage if interrupted by some
  61.        signals - so we handle it by calling time() ourself */
  62.     time_t start, now;
  63.     int len;
  64.     
  65.     time(&start);
  66.     len = timeout;
  67.     
  68.     while (len > 0)
  69.     {
  70. sleep(len);
  71. time(&now);
  72. len = timeout - (now - start);
  73.     }
  74. }
  75. int s_read(int fd, char *buf, int len)
  76. {
  77.     int s = 0;
  78.     int n_read = 0;
  79.     do
  80.     {
  81. buf += s;
  82. errno = 0;
  83. while ((s = read(fd, buf, len)) < 0 && errno == EINTR)
  84.     errno = 0;
  85. if (s > 0)
  86.     n_read += s;
  87.     } while (s > 0 && (len -= s) > 0);
  88.     return s >= 0 ? n_read : s;
  89. }
  90. int s_write(int fd, char *buf, int len)
  91. {
  92.     int s = 0;
  93.     int n_written = 0;
  94.     do
  95.     {
  96. buf += s;
  97. errno = 0;
  98. while ((s = write(fd, buf, len)) < 0 && errno == EINTR)
  99.     errno = 0;
  100. if (s > 0)
  101.     n_written += s;
  102.     } while (s >= 0 && (len -= s) > 0);
  103.     
  104.     return s >= 0 ? n_written : s;
  105. }
  106. struct rtinfo
  107. {
  108.     int fd;
  109.     int rbytes;
  110. };
  111. void *read_thread(void *data)
  112. {
  113.     struct rtinfo *rip = data;
  114.     int len;
  115.     char buffer[65536];
  116.     if (debug)
  117. printf("read_thread(), fd=%dn", rip->fd);
  118.     do
  119.     {
  120. len = s_read(rip->fd, buffer, sizeof(buffer));
  121. if (len < 0)
  122. {
  123.     perror("read");
  124.     return NULL;
  125. }
  126. rip->rbytes += len;
  127.     } while (len > 0);
  128.     if (debug)
  129. printf("read_thread(), rbytes=%dn", rip->rbytes);
  130.     
  131.     return rip;
  132. }
  133. static void *test_thread(void *misc)
  134. {
  135.     char *rqbuf, *cp, *url;
  136.     int status, rqlen, len, val, fd, requests;
  137.     int bytes, rbytes, failed_requests, ki;
  138.     double min_time, max_time, total_time, dt;
  139.     double min_ctime, max_ctime, total_ctime, cdt;
  140.     struct timeval start_time, stop_time, connect_time, setup_time;
  141.     thread_t read_tid;
  142.     struct rtinfo rib;
  143.     
  144.     if (debug)
  145. printf("test_thread(): Startn");
  146.     
  147.     url = (char *) misc;
  148.     requests = 0;
  149.     failed_requests = 0;
  150.     min_time = -1.0;
  151.     max_time = 0.0;
  152.     total_time = 0.0;
  153.     bytes = 0;
  154.     
  155.     min_ctime = -1.0;
  156.     max_ctime = 0.0;
  157.     total_ctime = 0.0;
  158.     rqbuf = (char *) alloca((64+strlen(url))*keepalive);
  159.     rqbuf[0] = '';
  160.     
  161.     for (ki = 0; ki < keepalive; ki++)
  162.     {
  163. cp = rqbuf+strlen(rqbuf);
  164. if (ki+1 < keepalive)
  165. {
  166.     sprintf(cp, "GET %s HTTP/1.0rnConnection: Keep-AlivernAccept: */*rnrn", url);
  167. }
  168. else
  169. {
  170.     if (http_0)
  171. sprintf(cp, "GET %srn", url);
  172.     else
  173. sprintf(cp, "GET %s HTTP/1.0rnAccept: */*rnrn", url);
  174. }
  175.     }
  176.     
  177.     rqlen = strlen(rqbuf);
  178.     
  179.     while (!stop_flag)
  180.     {
  181. rbytes = 0;
  182. gettimeofday(&start_time, NULL);
  183. while ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 &&
  184.        errno == EINTR)
  185.     ;
  186. if (fd < 0)
  187. {
  188.     perror("socket");
  189.     return NULL;
  190. }
  191. if (rcvbuf_size > 0)
  192. {
  193.     val = rcvbuf_size;
  194.     setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *) &val, sizeof(val));
  195. }
  196. val = 1;
  197. setsockopt(fd, 6, TCP_NODELAY, (void *) &val, sizeof(val));
  198. gettimeofday(&setup_time, NULL);
  199. while ((status = connect(fd, 
  200.  (struct sockaddr *) &server_addr,
  201.  sizeof(server_addr))) < 0 && errno == EINTR)
  202.     ;
  203. if (status < 0)
  204. {
  205.     perror("connect");
  206.     failure = 1;
  207.     return NULL;
  208. }
  209. gettimeofday(&connect_time, NULL);
  210. if (debug)
  211.     printf("test_thread(), Connectedn");
  212.    
  213. rib.fd = fd;
  214. rib.rbytes = 0;
  215. if (thr_create(NULL,
  216.        0,
  217.        (void *(*)(void *)) read_thread,
  218.        (void *) &rib,
  219.        (bound_threads ? THR_BOUND : 0),
  220.        &read_tid))
  221. {
  222.     perror("thr_create");
  223.     exit(1);
  224. }
  225. len = s_write(fd, rqbuf, rqlen);
  226. if (len < 0)
  227. {
  228.     if (errno != EPIPE)
  229.     {
  230. perror("ptester: write");
  231. return NULL;
  232.     }
  233. }
  234. if (shutdown(fd, 1) < 0)
  235. {
  236.     perror("shutdown");
  237.     return NULL;
  238. }
  239. if (debug)
  240.     printf("test_thread(), Waiting for join (fd=%d)n", fd);
  241. if (thr_join(read_tid, NULL, NULL))
  242.     perror("thr_join");
  243. rbytes = rib.rbytes;
  244. if (debug)
  245.     printf("test_thread(), Got join (rbytes=%d)n", rbytes);
  246. if (rbytes == 0)
  247.     failed_requests += keepalive;
  248. else if (expected_bytes > 0 && rbytes != expected_bytes)
  249. {
  250.     fprintf(stderr, "Got %d (expected %d) bytesn",
  251.     rbytes, expected_bytes);
  252.     rbytes = 0;
  253. }
  254. bytes += rbytes;
  255. if (debug)
  256.     printf("test_thread(), Closing down (fd=%d)n", fd);
  257. while (close(fd) < 0 && errno == EINTR)
  258.     ;
  259. gettimeofday(&stop_time, NULL);
  260. dt = ((double) stop_time.tv_sec +
  261.       (double) stop_time.tv_usec / 1000000.0)-
  262.   ((double) setup_time.tv_sec +
  263.    (double) setup_time.tv_usec / 1000000.0);
  264. if (min_time < 0)
  265.     min_time = dt;
  266. else if (dt < min_time)
  267.     min_time = dt;
  268. if (dt > max_time)
  269.     max_time = dt;
  270. total_time += dt;
  271. cdt = ((double) connect_time.tv_sec +
  272.        (double) connect_time.tv_usec / 1000000.0) -
  273.    ((double) setup_time.tv_sec +
  274.     (double) setup_time.tv_usec / 1000000.0);
  275. if (min_ctime < 0)
  276.     min_ctime = cdt;
  277. else if (cdt < min_ctime)
  278.     min_ctime = cdt;
  279. if (cdt > max_ctime)
  280.     max_ctime = cdt;
  281. total_ctime += cdt;
  282. requests += keepalive;
  283.     }
  284.     mutex_lock(&result_lock);
  285.     total_nrq += requests;
  286.     total_bytes += bytes;
  287.     total_failed += failed_requests;
  288.     
  289.     if (max_time > max_tx)
  290. max_tx = max_time;
  291.     if (min_time < min_tx || min_tx == 0.0)
  292. min_tx = min_time;
  293.     
  294.     printf("%-19s %4d  %.4f %.4f %.4f  %.4f %.4f %.4f  %dn",
  295.    url, requests-failed_requests,
  296.    
  297.    min_ctime,
  298.    total_ctime / (double) (requests-failed_requests),
  299.    max_ctime,
  300.    
  301.    min_time,
  302.    total_time / (double) (requests-failed_requests),
  303.    max_time,
  304.    
  305.    bytes/(requests-failed_requests));
  306.     
  307.     mutex_unlock(&result_lock);
  308.     if (use_exit)
  309. thr_exit(NULL);
  310.     return NULL;
  311. }
  312. int mksockaddr_in(const char *host,
  313.   char *service,
  314.   struct sockaddr_in *sin)
  315. {
  316.     memset(sin, 0, sizeof(sin));
  317.     
  318.     sin->sin_family = AF_INET;
  319.     if (isdigit(host[0]))
  320. sin->sin_addr.s_addr = inet_addr(host);
  321.     else
  322.     {
  323. struct hostent hp;
  324. int h_errno;
  325. char buf[2048];
  326. if (gethostbyname_r(host, &hp, buf, sizeof(buf), &h_errno) == NULL)
  327.     return -1;
  328. memcpy(&sin->sin_addr, hp.h_addr_list[0], hp.h_length);
  329.     }
  330.     if (isdigit(service[0]))
  331. sin->sin_port = htons(atoi(service));
  332.     else
  333.     {
  334. struct servent sp;
  335. char buf[2048];
  336. if (getservbyname_r(service, "tcp", &sp, buf, sizeof(buf)) == NULL)
  337.     return -1;
  338. sin->sin_port = sp.s_port;
  339.     }
  340.     return 0;
  341. }
  342. int help(char *argv0)
  343. {
  344.     printf("Usage: %s [<options>]* <url> [<url>]*nn", argv0);
  345.     puts("Option  tDefaultttDescription");
  346.     puts("------- t---------------t-----------------------------------");
  347.     puts("-H      tttDisplay this information");
  348.     printf("-h<host>t%-15s Server host to connect ton",
  349.    server_host);
  350.     printf("-p<port>t%-15s Server port to connect ton",
  351.    server_port);
  352.     printf("-t<len> t%-15d Test length in secondsn",
  353.    test_length);
  354.     printf("-b<num> t%-15d Use bound threads if nonzeron",
  355.    bound_threads);
  356.     printf("-c<num> t%-15d Thread concurrency level if nonzeron",
  357.    concurrency);
  358.     printf("-R<num> t%-15d Receive socket buffer sizen",
  359.    rcvbuf_size);
  360.     printf("-e<num> t%-15d Check length of reply against this if nonzeron",
  361.    expected_bytes);
  362.     printf("-r<num> t%-15d Repeat each request this number of timesn",
  363.    repeat);
  364.     printf("-k<num> t%-15d Repeat each request inband (keepalive)n",
  365.    keepalive);
  366.     return 0;
  367. }
  368. int main(int argc,
  369.  char *argv[])
  370. {
  371.     int i, j, t;
  372.     int n_tids = 0;
  373.     thread_t tid[256];
  374.     time_t start_time, stop_time;
  375.     
  376.     signal(SIGPIPE, SIG_IGN);
  377.     
  378.     for (i = 1; i < argc && argv[i][0] == '-'; i++)
  379. switch (argv[i][1])
  380. {
  381.   case '?':
  382.   case 'H':
  383.     exit(help(argv[0]));
  384.     break;
  385.   case 'd':
  386.     debug = atoi(argv[i]+2);
  387.     break;
  388.     
  389.   case 'R':
  390.     rcvbuf_size = atoi(argv[i]+2);
  391.     break;
  392.     
  393.   case 't':
  394.     test_length = atoi(argv[i]+2);
  395.     break;
  396.     
  397.   case 'h':
  398.     server_host = argv[i]+2;
  399.     break;
  400.   case 'p':
  401.     server_port = argv[i]+2;
  402.     break;
  403.   case 'b':
  404.     if (isdigit(argv[i][2]))
  405. bound_threads = atoi(argv[i]+2);
  406.     else
  407. bound_threads = 1;
  408.     break;
  409.   case 'c':
  410.     concurrency = atoi(argv[i]+2);
  411.     break;
  412.   case 'E':
  413.     use_exit = 1;
  414.     break;
  415.     
  416.   case 'e':
  417.     expected_bytes = atoi(argv[i]+2);
  418.     break;
  419.   case 'r':
  420.     repeat = atoi(argv[i]+2);
  421.     break;
  422.   case 'k':
  423.     keepalive = atoi(argv[i]+2);
  424.     break;
  425.   case '0':
  426.     http_0 = 1;
  427.     break;
  428.     
  429.   default:
  430.     fprintf(stderr, "%s: unknown switch '%s', try -H for helpn",
  431.     argv[0], argv[1]);
  432.     exit(1);
  433. }
  434.     keepalive++;
  435.     
  436.     mutex_init(&result_lock, USYNC_THREAD, NULL);
  437.     if (mksockaddr_in(server_host, server_port, &server_addr) < 0)
  438.     {
  439. fprintf(stderr, "Error creating socket addressn");
  440. exit(1);
  441.     }
  442.     
  443.     fprintf(stderr, "Running test: ");
  444.     for (t = 0; t < test_length; t++)
  445.       {
  446. if (t % 10)
  447.   putc('-', stderr);
  448. else
  449.   putc('+', stderr);
  450.       }
  451.     fprintf(stderr, "rRunning test: ");
  452.     if (concurrency > 0)
  453. thr_setconcurrency(concurrency);
  454.     time(&start_time);
  455.     
  456.     for (; i < argc; i++)
  457.     {
  458. for (j = 0; j < repeat; j++)
  459. {
  460.     if (thr_create(NULL,
  461.    0,
  462.    (void *(*)(void *)) test_thread,
  463.    (void *) argv[i],
  464.    (bound_threads ? THR_BOUND : 0) +
  465.    THR_NEW_LWP,
  466.    &tid[n_tids]))
  467.     {
  468. perror("thr_create");
  469. exit(1);
  470.     }
  471.     
  472.     n_tids++;
  473. }
  474.     }
  475.     for (t = 0; t < test_length; t++)
  476.     {
  477. xsleep(1);
  478. putc('>', stderr);
  479. fflush(stdout);
  480.     }
  481.     
  482.     putc('n', stderr);
  483.     putc('n', stderr);
  484.     
  485.     printf("%-19s %4s  %6s %6s %6s  %6s %6s %6s  %sn",
  486.    "URL", 
  487.    "NRq",
  488.    "Min Ct",
  489.    "Avg Ct",
  490.    "Max Ct",
  491.    "Min Tx",
  492.    "Avg Tx",
  493.    "Max Tx",
  494.    "Bytes");
  495.     stop_flag = 1;
  496.     for (i = 0; i < n_tids; i++)
  497. thr_join(tid[i], NULL, NULL);
  498.     if (failure)
  499. exit(1);
  500.     
  501.     time(&stop_time);
  502.     test_length = (int) stop_time - (int) start_time;
  503.     
  504.     putchar('n');
  505.     printf("Actual test time.. %d secondsn", test_length);
  506.     
  507.     printf("Total requests.... %d (%d requests/sec)n",
  508.    total_nrq,
  509.    total_nrq / test_length);
  510.     
  511.     printf("Total failed...... %d (%d requests/sec)n",
  512.    total_failed,
  513.    total_failed / test_length);
  514.     
  515.     printf("Total bytes....... %d (%d bytes/sec)n",
  516.    total_bytes,
  517.    total_bytes / test_length);
  518.     
  519.     putchar('n');
  520.     printf("Min Tx: %.4fn", min_tx);
  521.     printf("Max Tx: %.4fn", max_tx);
  522.     
  523.     exit(0);
  524. }