Chapter 5. Creating server programs

Table of Contents
5.1. Introduction to server programs
5.2. The bind() API call
5.3. The listen() API call
5.4. The accept() API call
5.5. Our first server program
5.6. Testing server programs
5.7. Making our program end
5.8. The setsockopt() API call
5.9. The revised server program
Written by Scott Klement.

5.1. Introduction to server programs

The last few chapters have explained how to write a program that acts as a client to an existing server program. Now, we will begin exploring the other side of the connection, the server-side.

Usually the role of a client program is to initiate the network connection, to request services from the server, and then to terminate the connection. Most of the time, a client program becomes active when it is run by a user, and is deactivated when it is done processing the data it received from the server, or when the user tells it to deactivate.

In contrast, a server program usually stays active at all times. It does not initiate any activity on its own, but rather waits for connections from client programs. When a client program has connected, it waits for the client program to make requests. When the server program realizes that the client program is done, it waits for the next connection.

There are minor differences in which API calls you need to make when writing a server program versus writing a client program. You still need to call socket() to create a socket to use for communications, but instead of issuing a connect() call, you will listen() for connections, and then accept() the connections as they come in.

It's also important to understand that a client program has to know where the server program is listening for connections. (pause to let that sink in) In other words, when a client issues a connect(), it has to tell the API which address & port to connect to -- consequently, we have to make sure that the server is, in fact, listening on the port & address that the client expects it to be listening on. This is called 'binding' to a port.

In addition to the differences in which API is called, there are a few other considerations that make server programs different from client programs:

The basic model for a server program looks something like this:

  1. Call the getservbyname() API to find out the port number for the service you want to be a server for.

  2. Call the socket() API to create a new socket.

  3. Call the bind() API to bind the socket to the port that we found in step #1.

  4. Call the listen() API to tell the system that you want to listen for connections with this socket. (This "opens up" the port so that people can connect to it)

  5. Call the accept() API. The accept() API will wait until a client connects to the port, and then will create a new socket. The new socket will already be connected to the client.

  6. Here we process the newly connected client. Depending on whether we're only handling one connection at a time, or what model we're using to handle many connections, we'll do things very differently at this point.

  7. Close the socket you got from accept()

  8. Go back to step 5.