Sample Server

 < Day Day Up > 



Let’s now take a quick tour of a simple Sockets application. We focus first on the server, a simple Daytime protocol server. This server simply emits the date and time of the current host in string format to the client. This particular server uses stream sockets (provided by the TCP transport protocol). In Part II, we’ll look again at this application, and how it can be built using the other communications paradigms (datagram, multicast, and broadcast) in each language.

Note 

It should be noted that socket calls are not thread safe. Thread-safe versions do exist, so when operating in a threaded environment, thread calls should be used exclusively.

Source Discussion

The simple Daytime protocol server can be found in Listing 2.1 (line numbers added for the purpose of discussion). We first specify the header files that are necessary for compilation of the source (lines 1–5). This gives us access to socket types, symbolics, and a number of necessary host functions. Lines 7 and 8 define two internal symbolic constants, the maximum buffer size used to send our response, and the port that will be used to identify this server. Note that in this case, port 13 is the well-known port for the Daytime protocol.

Lines 10–15 begin our C main program and define some of our local variables to be used. We discuss each as they’re used within the program. Line 17 shows our first Sockets API call, socket. The socket call creates a new socket of family AF_INET (for Internet communication) and protocol SOCK_STREAM (the stream protocol, or TCP). This call creates a blank socket that we must now initialize prior to using.

Initialization of our new socket occurs in lines 19–25. After clearing out our address structure (servaddr), we define the family as AF_INET and then specify the incoming address and port. For the incoming address, we specify INADDR_ANY, which means that we’ll accept incoming connections through any of the interfaces on the host. The port is initialized with our daytime port number. Note the use of htonl (host-to-network-long) and htons (host-to-network-short). These functions provide the byte swapping to convert host-byte-order to network-byte-order (for either a 4-byte long or 2-byte short). These functions are commonly provided as macros, which may or may not provide any function depending upon whether the host-byte-order is the network-byte-order. Byte ordering is discussed later in this chapter. Finally, we bring our socket and address information together in the bind call. This call configures the socket based upon the data defined within the servaddr address structure.

At this point, we have an endpoint (half-association) configured. However, this endpoint is not available for incoming connections. In order to permit connections to be made, a call to the listen function is performed (line 27). This call permits incoming connections to be made and also defines the number of outstanding connections that are possible, in this case five.

Listing 2.1 Daytime protocol server (server.c).

start example
 1   #include <sys/socket.h>  2   #include <arpa/inet.h>  3   #include <stdio.h>  4   #include <time.h>  5   #include <unistd.h>  6  7   #define MAX_BUFFER            128  8   #define DAYTIME_SERVER_PORT    13  9 10   int main ( void ) 11   { 12     int serverFd, connectionFd; 13     struct sockaddr_in servaddr; 14     char timebuffer[MAX_BUFFER+1]; 15     time_t currentTime; 16 17     serverFd = socket(AF_INET, SOCK_STREAM, 0); 18 19     memset(&servaddr, 0, sizeof(servaddr)); 20     servaddr.sin_family = AF_INET; 21     servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 22     servaddr.sin_port = htons(DAYTIME_SERVER_PORT); 23 24     bind(serverFd,  25           (struct sockaddr *)&servaddr, sizeof(servaddr)); 26 27     listen(serverFd, 5); 28 29     while ( 1 ) { 30 31       connectionFd = accept(serverFd,  32                             (struct sockaddr *)NULL, NULL); 33 34       if (connectionFd >= 0) { 35 36         currentTime = time(NULL); 37         snprintf(timebuffer, MAX_BUFFER, "%s\n",  38                   ctime(&currentTime)); 39 40         write(connectionFd, timebuffer, strlen(timebuffer)); 41 42         close(connectionFd); 43 44       } 45 46     } 47 48   }
end example

At this point, we have a socket server configured and ready for incoming connections. The remainder of the program handles incoming connections and processes them based upon the Daytime protocol. Line 29 starts an infinite loop for connection handling. In order to now accept incoming connections, we use the accept call (lines 31 and 32). The accept call is unique to server applications, particularly stream connections (because no connection setup is performed for datagram connections). We specify our server socket (serverFd) and two NULL pointers. These NULL pointers could represent actual objects, which accept would fill in for information on the peer that connected. The accept call returns with a new socket (when a client connects), which represents a new preconfigured endpoint. This new socket represents the connection with the peer, which is used for Daytime protocol communication. It’s important to note here that our server socket (serverFd) is used solely for accepting new connections, but communicates no user data.

In line 34, a quick error check is made to ensure that a proper socket was returned. In the event an error occurred within the accept, a value of –1 would be returned.

Passing the socket error check, we build the data to be sent to the client (lines 36–38). The current date and time is gathered by the time call, which is converted into a string format using the ctime call. The call to sprintf copies this new string into our local buffer.

In line 40, we send the data to the client using the write call. We specify the socket, for the client connection, the data to emit, and the length of the data (computed using strlen).

Finally, we close the new client socket in line 42. Note that our server socket (serverFd) remains open and available for new incoming connections. The client socket, per the Daytime protocol, is closed directly after the data is sent. Per the stream protocol, the socket won’t be closed right away. Once the data is transmitted, and acknowledged by the peer, the socket is gracefully closed. Our while loop then continues back to line 31, where we call accept again awaiting a new client connection.



 < Day Day Up > 



BSD Sockets Programming from a Multi-Language Perspective
Network Programming for Microsoft Windows , Second Edition (Microsoft Programming Series)
ISBN: 1584502681
EAN: 2147483647
Year: 2003
Pages: 225
Authors: Jim Ohlund

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net