30.3 TCP Test Client
Figure
30.3 shows the client that we will use to test all the
variations of our server.
10鈥?2
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鈥?0
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 }
|