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);