I have a server that receives data from a client through a internet socket. When the connection is established, the server forks a process to deal with the connection. The child then reads data from the connection, does some stuff, responds to the client and waits for more data. The child dies when the connection is closed by the client. Works great on most of the systems, but I have one where the connections never seem to close and the children never die, but the client is opening new connections.

#Set things up to Listen for connection
$SIG{CHLD} = 'IGNORE';
my $listen_socket = IO::Socket::INET->new(LocalPort=>8000,
                                          Listen=>10,
                                          Proto=>'tcp',
                                          Reuse=>1);

die "Can't create a listening socket: $@" unless $listen_socket;

while (my $connection = $listen_socket->accept) {
    my $child;
    die "Can't fork: $!" unless defined ($child = fork());
    if ($child == 0) { #i'm the child!
        #only parent needs listening socket
        $listen_socket->close;
        while ($connection->read($chars, 2)) {
            #process the incomming request
$bytes = ord(substr($chars,0,1)) * 256 + ord(substr ($chars,1,1));
            $connection->read($request, $bytes);

                #do some stuff

            $connection->send($chars.$response);
            }
        }
    else { #i'm the parent
        $connection->close();
    }
}


I can think of two ways to deal with the zombie children.
1) limit the number of children, killing the oldest once that limit is reached. It would be simple enough to keep an array of PIDs for the children using push/shift and then kill to get rid of the oldest child. Killing processes seems messy though.

2) Having the child exit after a period of inactivity. I just can't figure this one out. I think I need to use alarm, the example being something like below, but I think the alarm should be on the $connection->read($chars,2) of the second while() above.

   eval {
        local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
        alarm $timeout;
        $nread = sysread SOCKET, $buffer, $size;
        alarm 0;
    };
    if ($@) {
        die unless $@ eq "alarm\n";   # propagate unexpected errors
        # timed out
    }
    else {
        # didn't
    }

Can I implement a eval/die pair as part of the while() conditional or do I need to move the read outside of the conditional and test that the connection is open, $chars is defined/valid and alarm didn't trigger?






--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to