distSOCKET/tcpserver.c

///////////////////////////////////////////////////////////////////////////////
// Filename: tcpserver.c
///////////////////////////////////////////////////////////////////////////////
// Purpose: show how to use TCP (this file: TCP server) (socket version)
//          uses tcpclient(.c) as TCP client
///////////////////////////////////////////////////////////////////////////////
// History:
// ========
//
// Date     Time     Name      Description   
// -------- -------- --------  ------------------------------------------------
// 96/02/20 09:40:57 muellerg: created
// 96/02/21 05:31:36 muellerg: documentation cleanup
// 96/03/19 05:13:20 muellerg: functionality added
///////////////////////////////////////////////////////////////////////////////


// Feature test switches ///////////////////////////// Feature test switches //
    /* NONE */



// System headers /////////////////////////////////////////// System headers //

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#ifndef sun
#include <strings.h>
#endif
#include <unistd.h>
#include <sys/wait.h>



// Local headers ///////////////////////////////////////////// Local headers //

#include "../common.h"



// Macros /////////////////////////////////////////////////////////// Macros //
    /* NONE */



// File scope objects /////////////////////////////////// File scope objects //

const int BACKLOG = 5;      // maximum number of pending connections



// External variables, functions, and classes ///////////// External objects //
    /* NONE */



// Signal catching functions ///////////////////// Signal catching functions //
    /* NONE */



// Structures, unions, and class definitions /////////////////// Definitions //
    /* NONE */



// Functions and class implementation /// Functions and class implementation //

/*
 * read and return all incoming data (a echo server)
 */

void do_it(int sockfd)
{
    int     n;
    char    buffer[MAXLINE];

    cout << "TCP server: receiving data:" << endl;

    while(true)
    {
        n = readline(sockfd, buffer, MAXLINE);
        if(n)
        {
            if (n < 0)
                error.system("TCP server: read error");
            else
            {
                // output buffer
                cout << buffer << endl;

                // write result back to sender  
                if (writen(sockfd, buffer, n) != n)
                    error.system("TCP server: write error");
            }
        }
        else
            return;     // connection closed
    }
}


// Main /////////////////////////////////////////////////////////////// Main //




/*
 * Example of a concurrent server using the TCP protocol
 *
 * paramteters:
 *
 *   argv[1]: port number to bind() & listen() to
 */

int
main(int argc, char *argv[])
{
    error.set_program_name(argv[0]);    

    if(argc!=2)
    {
        cerr << "Usage: " << argv[0] << " port" << endl;
        exit(EXIT_FAILURE);
    }

    // establish a function that changes the signalhandler
    // to report child death so that they can be catched and 
    // zombie processes are avoided

#ifndef hpux
    catch_children();
#endif


    int sockfd, newsockfd, clilen, childpid;
    struct sockaddr_in  cli_addr, serv_addr;
    int portnumber=-1;


    // get port number

    portnumber = atoi(argv[1]);
    if(portnumber <1)
    {
        cerr << "illegal port number" << endl;
        exit(EXIT_FAILURE);
    }


    // create a TCP socket (an Internet stream socket)

    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        error.system("server: can't create stream socket");


    // bind local address so that the client can send to us

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family      = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port        = htons(portnumber);

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
        error.system("server: can't bind local address");

    // listen for connection on socket with a maximum length of
    // pending connections of 5 (normal limited to 5)

    listen(sockfd, BACKLOG);


    while(true)
    {
        
        // wait for a connection from a client process.
        // This server is an example of a concurrent server.
         
        clilen = sizeof(cli_addr);


        // check for zombies

        waitpid(WAIT_ANY, NULL, WNOHANG);


        // accept connection

        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

        if (newsockfd < 0)
            error.system("server: accept error");


        // spawn child process to handle request
    
        if ( (childpid = fork()) < 0)
            error.system("server: fork error");
        else
            if (childpid == 0)
            {   // child process 
    
                close(sockfd);          // close original socket 
    
                do_it(newsockfd);       // process the request

                return(EXIT_SUCCESS);   // and exit..
            }

        close(newsockfd);               // parent process: close socket
                                        // to be able to reuse it for the
                                        // next connection
    }
}