Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Feb 2003 11:39:53 -0700
From:      G-der <gder@gder.net>
To:        freebsd-hackers@freebsd.org
Subject:   Properly reaping children from a fork()
Message-ID:  <20030224183953.GB80651@gder.net>

next in thread | raw e-mail | index | archive | help
I wasn't sure which group to send this too but -hackers seemed more 
appropriate than -questions.  I've started to play with sockets 
under FreeBSD and have created a very simple server.  All it does is 
listens (on port 2525 by default) and when it receives a connection 
fork()s.  The only purpose it is accept a string, print it to stdout along 
with the number of bytes received.

This is a first attempt for me but I seem to have problems when it comes 
to ensuring that all the children exit like they should.  What happens is 
that each child process remains in a zombied state (as seen through ps).  
Also if you check sockstat you can see that each zombied process still has 
a connection open.

I'm not sure if the problem is how I am trying to close the socket or if 
it is with my signal handling.  I'm currently reading through intro(2) to 
see if there is something simple I've missed.

I've attached the code for your enjoyment...I'm sure someone will be able 
to point out my mistake pretty quickly.  Also I've found a couple of web 
pages that kind of explain socket handling but am looking for other 
resources that I can consult.

Thanks in advance, I'm not a normal subscriber to -hackers so a cc to 
gder@gder.net would be appreciated.

Regards

Gene Dinkey
gder@gder.net

--CUT HERE--

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

#define MYPORT                  2525
#define MAXRECV         5
#define MAXBUFSIZE      50

int main ( void );
int establish ( unsigned short portnum );
int get_connect ( int sockfd );
int  get_data ( int sockfd );
void sigchld_handler ( int s );


int main ( void )
{
        int s;
//      struct sigaction sa;

        if ((s=establish(MYPORT)) < 0)          //establish the socket
                exit(-1);

        s = get_connect(s);                                             //wait for a connection


/* The commented code was supposed to reap the children in but it didn't
   the call to signal() is supposed to do the same thing, but it doesn't */

/*      sa.sa_handler = sigchld_handler;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = SA_RESTART;
   if (sigaction(SIGCHLD, &sa, NULL) == -1) {
      perror("main:sigaction");
      exit(-1);
      }                         */

        signal(SIGCHLD, sigchld_handler);

        if (s != -1) {
                get_data(s);            // get the incoming data
                close(s);                       // finally close the socket
                }
        exit(0);
}

/*handles zombied processes*/
void sigchld_handler ( int s )
{
        while(waitpid(-1, NULL, WNOHANG) > 0);
}


/* Establishses a socket and starts to listen */
int establish ( unsigned short portnum )
{
   int sockfd;
   struct sockaddr_in my_addr;

   if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {                //establish the socket
                perror("establish:socket");
                return(-1);
                }

        /* host information */
   my_addr.sin_family = AF_INET;
   my_addr.sin_port = htons(portnum);
   my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
   memset(&(my_addr.sin_zero), '\0', 8);

        /* bid the socket to a port */
   if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) < 0) {
                perror("establish:bind");
                return(-1);
                }

        /* finally tell the socket to start listening */
        if (listen(sockfd, MAXRECV) < 0) {
                perror("establish:listen");
                close(sockfd);
                return(-1);
                }

   return(sockfd);              // return the socket handler
}


/*accepts connections*/
int get_connect ( int sockfd )
{
        int sin_size, new_fd;
        struct sockaddr_in their_addr;

        sin_size = sizeof(struct sockaddr_in);

        for(;;) {               //begin the accept loop

        /* accept the new connection and get the new socket id */
        if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) < 0) {
                perror("get_connect:accept");
                return(-1);
                }
        printf("Server got connection\n");

        /* fork the new connection */
        if(!fork()) {
                close(sockfd);          // close the listener, child doesn't need it 
                return(new_fd); // return the new active socket
                }
        }
        return(-1);
}

/*gets some data and prints it out*/
int get_data ( int sockfd )
{
        char buffer[MAXBUFSIZE];
        int datain;

        for (;;) {                      //begin the retreival loop

        /* get the incoming data and check a few things */
        if ((datain = recv(sockfd, buffer, MAXBUFSIZE, 0)) < 0) {
                perror("get_data:recv");
                return(-1);
                }
        else if (datain > 0) {          //print number of bytes received
                printf("Received %d bytes\n", datain);
                buffer[datain] = '\0';
                }
        else if (datain == 0)           //if 0 then return and close the socket
                return(0);

        printf("%s", buffer);           //otherwise print the buffer
        }
        return(0);
}

--EOF--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030224183953.GB80651>