I'm developing a special purpose mailer for internal company use. The
application is being developed, and will run on Windows 2000. It is a
requirement that there be multiple processes all listening on port 25 for
inbound connections.
Two weeks ago, my program would fork() every time it received a connection.
This worked great until I discovered that I can only fork() 64 processes, even
if those processes terminate, before Perl refuses to fork any more processes
with $! = "resource temporarily unavailable". I'm quite sure the children are
being cleaned up properly.
This week I said "a ha!" I'll just pre-fork 16 children all listening on port
25, and each will handle a new connection after it finishes with the current
one. Unfortunately, only the first process (and it is always the first)
actually receives connections. If it is busy, the other 15 children do nothing.
I have spent a great deal of time on this, both reading docs and experimenting.
It seems that Satan himself has cursed this project. I tried setting up the
socket in the parent process like I did when I forked for each connection. That
did not work; apparently if the child is listening, it must also setup the
socket.
I also tried running multiple CMD boxes each running a non-forking version of
the code, but only the first instance will receive and process connections.
Is there some fundamental thing I'm missing about listening for connections,
like only one process can do it? Sorry about the long post- I thought more
background would be better than less. The pertinent parts of the code are below:
Each child does this immediately after being forked:
# Define an internet tcp stream socket with the name SERVER.
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
# Configure the socket so it can be restarted rapidly.
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1);
# Create the socket address.
$my_addr = sockaddr_in($listen_port, INADDR_ANY);
# Register the SERVER address with the operating system.
bind(SERVER, $my_addr) or die "can not bind to port $listen_port: $!\n";
# establish a queue for inbound connections.
listen(SERVER, SOMAXCONN) or die "can not listen on port $listen_port: $!\n";
$sin = ''; vec($sin, fileno(SERVER), 1) = 1;
The child processing loop looks like this:
for (;;)
{
# If there is data queued on an inbound client connection,
# then we will enter this routine.
$nfound = select($sout = $sin, undef, undef, .25);
if (vec($sout, fileno(SERVER), 1))
{
$client_addr = accept(CLIENT, SERVER);
($client_socket, $client_pip) = sockaddr_in($client_addr);
if ($client_pip)
{
# Get hostname of client via dns lookup of ip address.
$client_name = gethostbyaddr($client_pip, AF_INET);
$client_ip = inet_ntoa($client_pip);
print ":: $$ connected to $client_name/$client_ip on socket
$client_socket\n";
}
}
}
_______________________________________________
ActivePerl mailing list
[email protected]
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs