Unix Network Programming Manual
Client-Server Mechanisms
Example1
was specifically referred to as a client program that
connected to a server. This is a common model in network programs,
where one program (the server) runs, waiting for some other program
(the client) to request a service. Not only is this a useful paradigm for
many applications (ftp, web services, telnet), it also helps ease the
programming burden by prescribing the synchronization between the two
programs.
The synchronization requirement is that the two end-points of the
communications know exactly what point in the process the other is at.
This does not mean that it knows what the next message contains, only
that the contents meet certain conditions. For example, an automatic
teller machine server would expect that after it sends a message asking
for a withdrawal amount, the next message will contain an amount.
As you might expect, the client and server have slightly different
programming requirements, since they perform different functions. For
example, the server doesn't need to connect to anything, that is the
client's responsibility, but the server does have to make itself available
for such connections. The following program shows a server program
that corresponds to the client1 program.
The calls that are of interest are
bind,
listen, and
accept.
The bind call is discussed in the
bind page. The listen call
simply tells
the operating system that the socket is now complete and ready for use, and
that it is used to receive messages. This is useful if a server has a lot
of initializing to do after the socket is bound, and doesn't want any
connections. The return from the listen is -1 for an error.
The accept call causes the server process to wait for a connection to
arrive. The syntax of the call is:
s = accept (socket, addr, addrsize)
int socket
struct sockaddr addr
int addrsize
address is the address of the machine where the connecting client is
executing, and addrsize is the size of that address in bytes. addrsize
needs to be set to the maximum possible size allowed before making the call,
and then it is set to the actual size returned.
The server does not proceed until a client process issues a
connect request to the correct address and socket.
The return from the connect call is a new socket. This is confusing to
new programmers, but makes a lot of sense. Servers usually server lots
of people. A web server that could only server one client at a time
would not be very useful. So the original socket is reserved for making
connections, and then each new client is assigned a different socket so that
the server can easily differentiate between them. In this simple application
it seems foolish, but is very useful in real applications.