Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Can I timeout an accept call?

by Declarent (Sexton)
on Jun 10, 2002 at 04:44 UTC ( [id://173034]=perlquestion: print w/replies, xml ) Need Help??

Declarent has asked for the wisdom of the Perl Monks concerning the following question:

I have a lovely server working that accepts client connections, forks off a nice module and processes their data. Then, the client nicely hangs up and the child exits.

However, if the client is disconnected before it signals that it's done, the child stays around forever waiting for input.

This leads to quite the population explosion.

I'm using the classic sockets-with-select loop for input, but I can't seem to get a timeout working.

My problem seems to be with the accept call which doesn't ever timeout, even when setting the timeout value in the socket definition. This must be a pretty common issue, so what do you guys do?

I'll be happy to post a snippet of code, but it's a textbook listener using IO::Select for multiple connections.

Declarent

Replies are listed 'Best First'.
Re: Can I timeout an accept call?
by virtualsue (Vicar) on Jun 10, 2002 at 09:31 UTC
    A snippet would have been nice, but I think the answer is relatively simple - avoid the problem altogether by setting the socket to operate in non-blocking mode with fcntl. Once you've done this, when you call accept on that socket and there is no connection actually waiting there, then it should return undef and set $! to EWOULDBLOCK.
    use Fcntl qw/F_GETFL, F_SETFL, O_NONBLOCK/; $flags = fcntl(SOCK_HANDLE, F_GETFL, 0) or die "Can't get flags for socket: $!"; $flags = fcntl(SOCK_HANDLE, F_SETFL, $flags | O_NONBLOCK) or die "Can't set flags for socket: $!";
    source: Programming Perl 3

      Many thanks to you, Monks!

      After much fiddling with the ideas here, I decided on another way of doing it. Here's what I decided:

      I'm using IO::Socket::INET, so my ports are defaulted to non-blocking. Sadly, that means that as soon as I get any connection from the client, I can get an undef on that port during a pause or after input during the next cycle. So that was out.

      I then set the port to block, and set the Timeout value, but it wouldn't time out for me at accept. Dunno why that is, I'm on *nix, so it should work. *shrug*

      So, I set the thing to block, and after the accept I added:

      $test=$data_port->peerhost(); if (not defined $test){close_data_port;}
      That way, during any client pause, the connection is still open, so peerhost returns it's IP address. When the connection drops, that value goes undef and I call my exit sub.

      Now, my population explosion is under control. Many Thanks!

      Declarent
        Unfortunately, non-blocking IO isn't as simple as blocking IO. I'm not sure why you say that your sockets are "defaulted to non-blocking" simply by virtue of using IO::Socket::INET. To my knowledge, sockets created from this module are not automatically placed in a non-blocking state unless you explicitly ask for them that way.

        To get around the fact that many of your non-blocking socket calls will immediately return (frequently with 'undef'), you should use IO::Select to detect when a socket has something for you, or when a socket is available to accept data. It's generally safe then to read from or write to a socket such that you won't block, and won't get 'undef' (unless it really means it).

        Unfortunately this logic tends to add a lot of additional complexity to your code. Fortunately, much of this has already been encapsulated in some Perl modules, POE being the most noteworthy.

Re: Can I timeout an accept call?
by choocroot (Friar) on Jun 10, 2002 at 07:35 UTC
    For timeout on accept() you can also use the "Timeout => $second" option when creating your socket (IO::Socket::INET):
    # create a socket with a 10 second timeout my $server_socket = IO::Socket::INET->new( LocalPort => 1234, Timeout => 10 ); my $client_socket = $server_socket->accept(); if( not defined $client_socket ) { print "Timeout ...\n"; } else { print "Process request ...\n" }
Re: Can I timeout an accept call?
by grep (Monsignor) on Jun 10, 2002 at 05:30 UTC
    If you are on *nix based system you have alarm and $SIG{ALRM} (no alarm on Win32). I do not know if this would be the best solution - I have not done socket programming for 4 years.

    grep
    Just me, the boy and these two monks, no questions asked.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://173034]
Approved by erikharrison
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2024-04-24 20:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found