[ Team LiB ] Previous Section Next Section

30.3 TCP Test Client

Figure 30.3 shows the client that we will use to test all the variations of our server.

10–12 Each time we run the client, we specify the hostname or IP address of the server, the server's port, the number of children for the client to fork (allowing us to initiate multiple connections to the same server concurrently), the number of requests each child should send to the server, and the number of bytes to request the server to return each time.

17–30 The parent calls fork for each child, and each child establishes the specified number of connections with the server. On each connection, the child sends a line specifying the number of bytes for the server to return, and then the child reads that amount of data from the server. The parent just waits for all the children to terminate. Notice that the client closes each TCP connection, so TCP's TIME_WAIT state occurs on the client, not on the server. This is a difference between our client/server and normal HTTP connections.

When we measure the various servers in this chapter, we execute the client as


% client 192.168.1.20 8888 5 500 4000

This creates 2,500 TCP connections to the server: 500 connections from each of five children. On each connection, 5 bytes are sent from the client to the server ("4000\n") and 4,000 bytes are transferred from the server back to the client. We run the client from two different hosts to the same server, providing a total of 5,000 TCP connections, with a maximum of 10 simultaneous connections at the server at any given time.

Sophisticated benchmarks exist for testing various Web servers. One is called WebStone and is available from http://www.mindcraft.com/webstone. However, we do not need anything this sophisticated to make some general comparisons of the various server design alternatives that we will examine in this chapter.

We now present the nine different server designs.

Figure 30.3 TCP client program for testing our various servers.

server/client.c

 1 #include    "unp.h"

 2 #define MAXN    16384     /* max # bytes to request from server */

 3 int
 4 main(int argc, char **argv)
 5 {
 6     int     i, j, fd, nchildren, nloops, nbytes;
 7     pid_t   pid;
 8     ssize_t n;
 9     char    request[MAXLINE], reply[MAXN];

10     if (argc != 6)
11         err_quit("usage: client <hostname or IPaddr> <port> <#children> "
12                   "<#loops/child> <#bytes/request>");

13     nchildren = atoi(argv[3]);
14     nloops = atoi(argv[4]);
15     nbytes = atoi(argv[5]);
16     snprintf(request, sizeof(request), "%d\n", nbytes); /* newline at end */

17     for (i = 0; i < nchildren; i++) {
18         if ( (pid = Fork()) == 0) { /* child */
19             for (j = 0; j < nloops; j++) {
20                 fd = Tcp_connect(argv[1], argv[2]);

21                 Write(fd, request, strlen(request));

22                 if ( (n = Readn(fd, reply, nbytes)) != nbytes)
23                     err_quit("server returned %d bytes", n);

24                 Close(fd);       /* TIME_WAIT on client, not server */
25             }
26             printf("child %d done\n", i);
27             exit(0);
28         }
29         /* parent loops around to fork() again */
30     }

31     while (wait(NULL) > 0)     /* now parent waits for all children */
32         ;
33     if (errno != ECHILD)
34         err_sys("wait error");

35     exit(0);
36 }
    [ Team LiB ] Previous Section Next Section