Server Connections

In the internet domain, the server process creates a socket, binds it to a well-known protocol port, and waits for requests. The listen() call allows server processes to prepare a socket for incoming connections. In terms of underlying protocols, the listen() call puts the socket in a passive mode ready to accept connections. When the server process starts the listen() call, it also informs the operating system that the protocol software should queue multiple simultaneous connection requests that arrive at a socket. The listen() call includes a parameter that allows a process to specify the length of the connection queue for that socket. If the queue is full when a connection request arrives, the operating system refuses the connection. The listen() call applies only to sockets that have selected reliable stream delivery or connection-oriented datagram service. An example of a server application using the listen() call is:
An Application Using the listen() Call

int s;
int backlog;
int rc;
...
rc = listen(s, 5);

The listen() call is used to indicate that the server is ready to begin accepting connections. In this example, a maximum of five connection requests can be queued for the server. Additional requests are ignored. For a more detailed description, see listen().

Once a socket has been set up, the server process needs to wait for a connection. The server process waits for a connection by using the accept() call. A call to the accept() call blocks until a connection request arrives. When a request arrives, the operating system returns the address of the client process that has placed the request. The operating system also creates a new socket that has its destination connected to the requesting client process and returns the new socket descriptor to the calling server process. The original socket still has a wildcard foreign destination which remains open.

When a connection arrives, the call to accept() returns. The server process can either handle requests interactively or concurrently. In the interactive approach, the thread that did the accept() handles the request itself, closes the new socket, and then starts the accept() call to obtain the next connection request. In the concurrent approach, after the call to accept() returns, the server process creates a new thread to handle the request. The new thread proceeds to service the request, and then exits. The original thread invokes the accept() call to obtain the next connection request.

An example of a server application for accepting a connection request by using the accept() call is:
An Application Using the accept() Call

int clientsocket;
int s;
struct sockaddr clientaddress;
int addrlen;
...
addrlen = sizeof(clientaddress);
...
clientsocket = accept(s, &clientaddress, &addrlen);


[Back: Obtaining Socket Addresses]
[Next: Handling Multiple Sockets]