[ Team LiB ] |
1.5 A Simple Daytime ServerWe can write a simple version of a TCP daytime server, which will work with the client from Section 1.2. We use the wrapper functions that we described in the previous section and show this server in Figure 1.9. Figure 1.9 TCP daytime server.intro/daytimetcpsrv.c 1 #include "unp.h". 2 #include <time.h> 3 int 4 main(int argc, char **argv) 5 { 6 int listenfd, connfd; 7 struct sockaddr_in servaddr; 8 char buff[MAXLINE]; 9 time_t ticks; 10 listenfd = Socket(AF_INET, SOCK_STREAM, 0); 11 bzeros(&servaddr, sizeof(servaddr)); 12 servaddr.sin_family = AF_INET; 13 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 14 servaddr.sin_port = htons(13); /* daytime server */ 15 Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); 16 Listen(listenfd, LISTENQ); 17 for ( ; ; ) { 18 connfd = Accept(listenfd, (SA *) NULL, NULL); 19 ticks = time(NULL); 20 snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); 21 Write(connfd, buff, strlen(buff)); 22 Close(connfd); 23 } 24 } Create a TCP socket10 The creation of the TCP socket is identical to the client code. Bind server's well-known port to socket11–15 The server's well-known port (13 for the daytime service) is bound to the socket by filling in an Internet socket address structure and calling bind. We specify the IP address as INADDR_ANY, which allows the server to accept a client connection on any interface, in case the server host has multiple interfaces. Later we will see how we can restrict the server to accepting a client connection on just a single interface. Convert socket to listening socket16 By calling listen, the socket is converted into a listening socket, on which incoming connections from clients will be accepted by the kernel. These three steps, socket, bind, and listen, are the normal steps for any TCP server to prepare what we call the listening descriptor (listenfd in this example). The constant LISTENQ is from our unp.h header. It specifies the maximum number of client connections that the kernel will queue for this listening descriptor. We say much more about this queueing in Section 4.5. Accept client connection, send reply17–21 Normally, the server process is put to sleep in the call to accept, waiting for a client connection to arrive and be accepted. A TCP connection uses what is called a three-way handshake to establish a connection. When this handshake completes, accept returns, and the return value from the function is a new descriptor (connfd) that is called the connected descriptor. This new descriptor is used for communication with the new client. A new descriptor is returned by accept for each client that connects to our server.
The current time and date are returned by the library function time, which returns the number of seconds since the Unix Epoch: 00:00:00 January 1, 1970, Coordinated Universal Time (UTC). The next library function, ctime, converts this integer value into a human-readable string such as Mon May 26 20:58:40 2003 A carriage return and linefeed are appended to the string by snprintf, and the result is written to the client by write.
Terminate connection22 The server closes its connection with the client by calling close. This initiates the normal TCP connection termination sequence: a FIN is sent in each direction and each FIN is acknowledged by the other end. We will say much more about TCP's three-way handshake and the four TCP packets used to terminate a TCP connection in Section 2.6. As with the client in the previous section, we have only examined this server briefly, saving all the details for later in the book. Note the following points:
|
[ Team LiB ] |