Next Previous Contents

4. Writing Server Applications (TCP/SOCK_STREAM)

4.1 How come I get "address already in use" from bind()?

You get this when the address is already in use. (Oh, you figured that much out?) The most common reason for this is that you have stopped your server, and then re-started it right away. The sockets that were used by the first incarnation of the server are still active. This is further explained in ``2.7 Please explain the TIME_WAIT state.'', and ``2.5 How do I properly close a socket?''.

4.2 Why don't my sockets close?

When you issue the close() system call, you are closing your interface to the socket, not the socket itself. It is up to the kernel to close the socket. Sometimes, for really technical reasons, the socket is kept alive for a few minutes after you close it. It is normal, for example for the socket to go into a TIME_WAIT state, on the server side, for a few minutes. People have reported ranges from 20 seconds to 4 minutes to me. The official standard says that it should be 4 minutes. On my Linux system it is about 2 minutes. This is explained in great detail in ``2.7 Please explain the TIME_WAIT state.''.

4.3 How can I make my server a daemon?

There are two approaches you can take here. The first is to use inetd to do all the hard work for you. The second is to do all the hard work yourself.

If you use inetd, you simply use stdin, stdout, or stderr for your socket. (These three are all created with dup() from the real socket) You can use these as you would a socket in your code. The inetd process will even close the socket for you when you are done.

If you wish to write your own server, there is a detailed explanation in "Unix Network Programming" by Richard Stevens (see ``1.5 Where can I get source code for the book [book title]?''). I also picked up this posting from comp.unix.programmer, by Nikhil Nair ( n201@cus.cam.ac.uk). You may want to add code to ignore SIGPIPE, because if this signal is not dealt with, it will cause your application to exit. (Thanks to ngo@milan2.snafu.de for pointing this out).

I worked all this lot out from the GNU C Library Manual (on-line documentation). Here's some code I wrote - you can adapt it as necessary:


  #include <stdio.h>
  #include <stdlib.h>
  #include <ctype.h>
  #include <unistd.h>
  #include <fcntl.h>
  #include <signal.h>
  #include <sys/wait.h>

  /* Global variables */
  volatile sig_atomic_t keep_going = 1; /* controls program termination */

  /* Function prototypes: */
  void termination_handler (int signum); /* clean up before termination */

  int
  main (void)
  {
    ...

    if (chdir (HOME_DIR))         /* change to directory containing data
                                      files */
     {
       fprintf (stderr, "`%s': ", HOME_DIR);
       perror (NULL);
       exit (1);
     }

     /* Become a daemon: */
     switch (fork ())
       {
       case -1:                    /* can't fork */
         perror ("fork()");
         exit (3);
       case 0:                     /* child, process becomes a daemon: */
         close (STDIN_FILENO);
         close (STDOUT_FILENO);
         close (STDERR_FILENO);
         if (setsid () == -1)      /* request a new session (job control) */
           {
             exit (4);
           }
         break;
       default:                    /* parent returns to calling process: */
         return 0;
       }

     /* Establish signal handler to clean up before termination: */
     if (signal (SIGTERM, termination_handler) == SIG_IGN)
       signal (SIGTERM, SIG_IGN);
     signal (SIGINT, SIG_IGN);
     signal (SIGHUP, SIG_IGN);

     /* Main program loop */
     while (keep_going)
       {
         ...
       }
     return 0;
  }

  void
  termination_handler (int signum)
  {
    keep_going = 0;
    signal (signum, termination_handler);
  }

4.4 How can I listen on more than one port at a time?

The best way to do this is with the select() call. This tells the kernel to let you know when a socket is available for use. You can have one process do i/o with multiple sockets with this call. If you want to wait for a connect on sockets 4, 6 and 10 you might execute the following code snippet:


       fd_set socklist;

       FD_ZERO(); /* Always clear the structure first. */
       FD_SET(4, );
       FD_SET(6, );
       FD_SET(10, );
       if (select(11, NULL, , NULL, NULL) < 0)
         perror("select");

The kernel will notify us as soon as a file descriptor which is less than 11 (the first parameter to select()), and is a member of our socklist becomes available for writing. See the man page on select() for more details.

4.5 What exactly does SO_REUSEADDR do?

This socket option tells the kernel that even if this port is busy (in the TIME_WAIT state), go ahead and reuse it anyway. If it is busy, but with another state, you will still get an address already in use error. It is useful if your server has been shut down, and then restarted right away while sockets are still active on its port. You should be aware that if any unexpected data comes in, it may confuse your server, but while this is possible, it is not likely.

It has been pointed out that "A socket is a 5 tuple (proto, local addr, local port, remote addr, remote port). SO_REUSEADDR just says that you can reuse local addresses. The 5 tuple still must be unique!" by Michael Hunter ( phunter@qnx.com). This is true, and this is why it is very unlikely that unexpected data will ever be seen by your server. The danger is that such a 5 tuple is still floating around on the net, and while it is bouncing around, a new connection from the same client, on the same system, happens to get the same remote port. This is explained by Richard Stevens in ``2.7 Please explain the TIME_WAIT state.''.

4.6 What exactly does SO_LINGER do?

On some unixes this does nothing. On others, it instructs the kernel to abort tcp connections instead of closing them properly. This can be dangerous. If you are not clear on this, see ``2.7 Please explain the TIME_WAIT state.''.

4.7 What exactly does SO_KEEPALIVE do?

From Andrew Gierth ( ndrew@erlenstar.demon.co.uk):

The SO_KEEPALIVE option causes a packet (called a 'keepalive probe') to be sent to the remote system if a long time (by default, more than 2 hours) passes with no other data being sent or received. This packet is designed to provoke an ACK response from the peer. This enables detection of a peer which has become unreachable (e.g. powered off or disconnected from the net). See ``2.8 Why does it take so long to detect that the peer died?'' for further discussion.

Note that the figure of 2 hours comes from RFC1122, "Requirements for Internet Hosts". The precise value should be configurable, but I've often found this to be difficult. The only implementation I know of that allows the keepalive interval to be set per-connection is SVR4.2.

4.8 How can I bind() to a port number < 1024?

From Andrew Gierth ( ndrew@erlenstar.demon.co.uk):

The restriction on access to ports < 1024 is part of a (fairly weak) security scheme particular to UNIX. The intention is that servers (for example rlogind, rshd) can check the port number of the client, and if it is < 1024, assume the request has been properly authorised at the client end.

The practical upshot of this, is that binding a port number < 1024 is reserved to processes having an effective UID == root.

This can, occasionally, itself present a security problem, e.g. when a server process needs to bind a well-known port, but does not itself need root access (news servers, for example). This is often solved by creating a small program which simply binds the socket, then restores the real userid and exec()s the real server. This program can then be made setuid root.

4.9 How do I get my server to find out the client's address / host-

name?

From Andrew Gierth ( ndrew@erlenstar.demon.co.uk):

After accept()ing a connection, use getpeername() to get the address of the client. The client's address is of course, also returned on the accept(), but it is essential to initialise the address-length parameter before the accept call for this will work.

Jari Kokko ( kokko@cc.hut.fi) has offered the following code to determine the client address:


  int t;
  int len;
  struct sockaddr_in sin;
  struct hostent *host;

  len = sizeof sin;
  if (getpeername(t, (struct sockaddr *) , ) < 0)
          perror("getpeername");
  else {
          if ((host = gethostbyaddr((char *) _addr,
                                    sizeof sin.sin_addr,
                                    AF_INET)) == NULL)
              perror("gethostbyaddr");
          else printf("remote host is '%s'\n", host->h_name);
  }

4.10 How should I choose a port number for my server?

The list of registered port assignments can be found in STD 2 or RFC


Next Previous Contents