|
#1
|
|||
|
|||
|
Hi,
Firstly, sorry to make my first post such a long one but this takes some explaining. I've searched all over for a solution so please forgive me if it's in a FAQ somewhere. I've got a socket problem with a daemon written in Perl. Like Sendmail and other daemons, my daemon accepts TCP connections and forks of subprocesses to deal with the incoming connections while keeping a master process in place to listen for more new connections. The fact that it can have several simultaneous incoming connections is vital. The problem is that if the master dies, the port doesn't get freed up so I can't start a new master. If there are child processes at the time the master process dies, one of them seems to bind to the port, though it's not really in a position to do anything useful with it as it's already busy dealing with a client connection. Indeed, if you do 'netstat -lnp' you can see one of the children is bound to the port after the master dies. In contrast, this doesn't happen in Sendmail, for example. With Sendmail, you can have 20 child processes dealing with incoming SMTP connections and you can kill the master and nothing ends up bound to port 25, yet (importantly) the existing child processes continue to run. You can then start a new master and it all starts working properly again. I don't know whether this is a limitation of the Perl socket library? I've managed to reproduce the problem with the simple code I have below. With my code below, you start it up and it listens on port 500. If you go to another shell and telnet in, you get a simple 30 second countdown. If you start up several shells and do the same in each, each one gets its own seperate countdown and it all works. If, however, in one of the shells you kill the master, the port then binds to one of the child processes, if there are any. The other countdowns continue as you'd expect them to but the port isn't freed until they have all finished. This is a real problem because it stops me starting a new master process to accept further incoming connections until all the children have ended. If anyone can shed any light on this I'd be ever so grateful. I keep revisiting this problem from time to time but I've never got to the bottom of it and it's driving me nuts! The socket code below is more or less a straight copy from one of the examples in one of the O'Reilly books ... but seems to have this infuriating fundamental flaw. I'm using Perl 5.8.0 FWIW. Code:
#!/usr/bin/perl
use strict;
use Socket;
use FileHandle;
my $port = 500;
my $proto = getprotobyname('tcp');
sub reaper
{ wait; $SIG{CHLD} = \&reaper; }
$SIG{CHLD} = \&reaper;
socket(Server, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die "setsockopt: $!";
bind(Server, sockaddr_in($port, INADDR_ANY)) or die "bind: $!";
listen(Server, SOMAXCONN);
my ($paddr, $kid);
for ( ; $paddr = accept(Client, Server); close Client)
{
if (!defined($kid=fork))
{ die "cannot fork: $!"; }
if ($kid)
{
# parent
}
else
{
Client->autoflush;
my($port, $iaddr) = sockaddr_in($paddr);
print "Welcome $iaddr on port $port\n";
for (my $i = 30; $i > 0; $i--)
{ print Client "countdown: $i\r\n"; sleep 1; }
exit;
}
}
print "quitting: $!\n";
__________________
Cheers, Kingsley. |
![]() |
| Thread Tools | Search this Thread |
| Display Modes | |
|
|