Listing 4. Datagram sockets example. Client Program.


/* getservice -- a datagram transmission example. client program. Works with 
 * the server program 'services'. The program asks the server 'services', which
 * is running on the same machine or in a remote host, for the presence of a 
 * specified service on the server machine. The server looks up the "/etc/services"
 * file and sends an answer to the client. If the service exists, the answer gives
 * its name, the port number and the protocol used.
 *
 *    Usage:   getservice  <server host name>
 */

#include   <sys/types.h>
#include   <sys/socket.h>
#include   <netinet/in.h>
#include   <netdb.h>
#include   <signal.h>
#include   <sys/errno.h>

#define    FAIL   1             
#define    SUCC   0             
 
#define    PORT_NUMBER   2228   /* arbitrarily chosen free port number
                                 * for client-server communication. Must
                                 * be the same in both client and server
                                 */

#define    MAXTRIES   3         /* maximum number of retransmissions before giving up */
#define    PROMPT     printf("Service Sought (ctrl-d to exit) : ")

/* ------------------------------------------------------------------- */

main(ac, av)
    int ac;   char **av ;
{
    int sock ;                       /* socket descriptor */
    struct sockaddr_in sock_addr ;   /* local socket address structure */
    char *progr_name = av[0] ;       /* the present program name */
    char *server_name = av[1] ;      /* server name given on command line */ 
    char service_name[30] ;          /* service name to be asked for */
    char return_message[256] ;       /* buffer for response from the server */
    struct hostent *host_struct, *gethostbyname() ;
    void error() ;                   /* the same as in listing 1 */
    int num_tries ;                  /* the current number of transmission retries */
    int alarm_handler() ;            /* the new alarm signal handler routine */
    extern int errno ;               /* system call error number */
    

    if (ac != 2)  {
        fprintf(stderr, "error -- usage: %s <server name>\n", progr_name) ;
        exit(FAIL) ;
    }

    /* get server address */
    if ((host_struct = gethostbyname(server_name)) == NULL)  {
        fprintf(stderr, "%s: unknown server %s\n", progr_name, server_name) ;
        exit(FAIL) ;
    }
    
    /* allocate a datagram socket descriptor */
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	error(progr_name, ": error opening socket") ;

    /* copy server address and type to socket structure */
    bcopy(host_struct->h_addr, (char *)&sock_addr.sin_addr.s_addr,
          host_struct->h_length) ; 
    sock_addr.sin_port = PORT_NUMBER ;
    sock_addr.sin_family = AF_INET ;

    /* redirect alarm signal to new signal handler */
    (void)signal(SIGALRM, alarm_handler) ;

    /* send messages to remote host */

    while (PROMPT, gets(service_name) != NULL)  {
        num_tries = 0 ;
        for ( ; ; )  {
            int nread ;
            if (sendto(sock, service_name, sizeof service_name, 0, 
                   (struct sockaddr *)&sock_addr, sizeof sock_addr ) == -1)
                error(progr_name, ": error sending datagram to remote host") ;

            /* the "recv" blocks until an answer from the server arrives. Since we
             * are in a connectionless environment, reliable transmission isn't
             * guaranteed. For this reason, and although lost packets are very
             * unlikely, we set up a timeout with the call to alarm. If the timeout
             * expires, we retransmit the nessage a maximum of MAX_TRIES times.
             * We also assume that messages can come only from the 'service' server,
             * otherwise "recvfrom should be used.
             */ 

            (void)alarm(5) ;
            if ((nread = recv(sock, return_message, sizeof return_message, 0)) <= 0)  {
                if (nread < 0 && errno != EINTR)  
                    error(progr_name, ": receive failed") ;
                if (num_tries++ < MAXTRIES)  
                    continue ;
                else  {
                    fprintf(stderr, "timeout: no response from %s\n", 
                            server_name) ;
                    exit(FAIL) ;
                }
            }
            else          /* got an answer from the server */
                break ;
        }
        (void)alarm(0) ;   /* turn off alarm clock */
        /* print out the server response */
        printf("%s\n", return_message) ;
    }
    putchar('\n') ;
    if (close(sock) == -1)
	error(progr_name, ": error closing socket") ;
    exit(SUCC) ;
}

/* --------------------------------------------------------------------- */

/* alarm_handler -- new handler for the alarm signal. The default action
 * associated with a signal is reset once caugth, so it must be reset
 * to the intended action each time.
 */

int alarm_handler()     
{
    (void)signal(SIGALRM, alarm_handler) ;
}

/* --------------------------------------------------------------------- */
