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>