Example: Use signals with blocking socket APIs

Signals allow you to be notified when a process or application becomes blocked.

Signals provide a time limit for blocking processes. In this example the signal occurs after five seconds on the accept() call. This call normally blocks indefinitely, but because there is an alarm set, the call only blocks for five seconds. Because blocked programs can hinder performance of an application or server, they can be used to diminish this impact. The following example shows you how to use signals with blocking socket APIs.
Note: Asynchronous I/O used in a threaded server model is preferable over the more conventional model.


This graphic shows the socket calls that are used in the example program that uses signals.

Socket flow of events: Use signals with blocking socket

The following sequence of function calls shows how you can use signals to alert the application when the socket has been inactive:

  1. The socket() function returns a socket descriptor representing an endpoint. The statement also identifies that the AF_INET (Internet Protocol) address family with the TCP transport (SOCK_STREAM) being used for this socket.
  2. After the socket descriptor is created, a bind() function gets a unique name for the socket. In this example, a port number is not specified because the client application does not connect to this socket. This code snippet can be used within other server programs that use blocking APIs, such as accept().
  3. The listen() function indicates a willingness to accept client connection requests. After the listen() function is issued, an alarm is set to go off in five seconds. This alarm or signal alerts you when the accept() call blocks.
  4. The accept() function accepts a client connection request. This call normally blocks indefinitely, but because there is an alarm set, the call only blocks for five seconds. When the alarm goes off, the accept call is completed with -1 and with an errno value of EINTR.
  5. The close() function ends any open socket descriptors.
Note: By using the code examples, you agree to the terms of the Code license and disclaimer information.
/******************************************************************/
/* Example shows how to set alarms for blocking socket APIs       */
/******************************************************************/

/******************************************************************/
/* Include files                                                  */
/******************************************************************/
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>

/******************************************************************/
/* Signal catcher routine.  This routine will be called when the  */
/* signal occurs.                                                 */
/******************************************************************/
void catcher(int sig)
{
   printf("   Signal catcher called for signal %d\n", sig);
}

/******************************************************************/
/* Main program                                                   */
/******************************************************************/
int main(int argc, char *argv[])
{
   struct sigaction sact;
   struct sockaddr_in addr;
   time_t t;
   int sd, rc;

/******************************************************************/
/* Create an AF_INET, SOCK_STREAM socket                          */
/******************************************************************/
   printf("Create a TCP socket\n");
   sd = socket(AF_INET, SOCK_STREAM, 0);
   if (sd == -1)
   {
      perror("   socket failed");
      return(-1);
   }

/******************************************************************/
/* Bind the socket.  A port number was not specified because      */
/* we are not going to ever connect to this socket.               */
/******************************************************************/
   memset(&addr, 0, sizeof(addr));
   addr.sin_family = AF_INET;
   printf("Bind the socket\n");
   rc = bind(sd, (struct sockaddr *)&addr, sizeof(addr));
   if (rc != 0)
   {
      perror("   bind failed");
      close(sd);
      return(-2);
   }

/******************************************************************/
/* Perform a listen on the socket.                                */
/******************************************************************/
   printf("Set the listen backlog\n");
   rc = listen(sd, 5);
   if (rc != 0)
   {
      perror("   listen failed");
      close(sd);
      return(-3);
   }

/******************************************************************/
/* Set up an alarm that will go off in 5 seconds.                 */
/******************************************************************/
   printf("\nSet an alarm to go off in 5 seconds. This alarm will cause the\n");
   printf("blocked accept() to return a -1 and an errno value of EINTR.\n\n");
   sigemptyset(&sact.sa_mask);
   sact.sa_flags = 0;
   sact.sa_handler = catcher;
   sigaction(SIGALRM, &sact, NULL);
   alarm(5);

/******************************************************************/
/* Display the current time when the alarm was set                */
/******************************************************************/
   time(&t);
   printf("Before accept(), time is %s", ctime(&t));

/******************************************************************/
/* Call accept.  This call will normally block indefinitely,      */
/* but because we have an alarm set, it will only block for       */
/* 5 seconds.  When the alarm goes off, the accept call will      */
/* complete with -1 and an errno value of EINTR.                  */
/******************************************************************/
   errno = 0;
   printf("   Wait for an incoming connection to arrive\n");
   rc = accept(sd, NULL, NULL);
   printf("   accept() completed.  rc = %d, errno = %d\n", rc, errno);
   if (rc >= 0)
   {
      printf("   Incoming connection was received\n");
      close(rc);
   }
   else
   {
      perror("   errno string");
   }

/******************************************************************/
/* Show what time it was when the alarm went off                  */
/******************************************************************/
   time(&t);
   printf("After accept(), time is %s\n", ctime(&t));
   close(sd);
   return(0);
}
Related concepts
Signals
Asynchronous I/O
Related reference
Example: Use asynchronous I/O
Related information
accept()
listen()
close()
socket()
bind()