Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Timeouts when reading from socket Filehandles?

by Anonymous Monk
on Aug 27, 2002 at 03:23 UTC ( [id://193076]=perlquestion: print w/replies, xml ) Need Help??

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

I have tried various methods including:
$line = <$socket>;
and sysread and recv to solve a problem I have with no luck.

I am writing a TCP client geared towards speed and effeciency using IO::Socket, and I want it to timeout on a socket and move on through the loop if it doesn't receive any data within a set period of time. However none of the above examples seemed to work, and when the remote side doesn't send any data, the client side just 'hangs' indefinately. I don't think IO::Select is what I need either, as the Filehandle (socket) can definately be read from okay, its just that there is nothing there to be read yet (as the remote side hasn't produced any information).

I have no control over the server side so my client needs to be able to handle this...

Thanks in advance,
-jonny

Replies are listed 'Best First'.
Re: Timeouts when reading from socket Filehandles?
by sauoq (Abbot) on Aug 27, 2002 at 06:05 UTC

    Read up on select() and have a look at IO::Select. In particular, have a look at the IO::Select's can_read() method. It will do what you want. You just have to specify a timeout.

    -sauoq
    "My two cents aren't worth a dime.";
    
      If that does not offer exactly what you are looking for, what I have always done (in other languages, never had to do sockets with perl) was create a thread to handle the information. Attach a buffer and every now and again read the buffer to see what is in it from your main loop. This assumes you have thread support compiled into your version of perl (My Admin at work is doing this very thing right now to solve a similar problem)
        Although threads are fun, using a thread to manage a socket is overkill. You can do just fine using IO::Select and a single process. UNIX people have been writing single-process socket handling applications for years, and they work very well.

        The problem with introducing threads is that you have to make sure your code is thread safe. As soon as you put two trains on the metaphorical track of your program, you're going to have to make sure you're not setting yourself up for disaster.
Re: Timeouts when reading from socket Filehandles?
by hiseldl (Priest) on Aug 27, 2002 at 13:15 UTC
    If you want to timeout the client request, you could wrap it in an eval,
    eval { local $SIG{ALRM} = sub { die "Timed Out" }; alarm 10; ### IO::Socket/Select function call goes here alarm 0; }; if ($@ and $@ !~ /Timed Out/) { die }
    this should give you a 10 second timeout on your function call.

    --
    hiseldl

      It might be smarter to save the old signal value outside the eval, and restore it after the eval. Yes, setting it local works fine. I totally agree with that much.

      If the eval crashes on any code between your alarm 10 and alarm 0, the eval breaks. Granted, you have code to check for errors, but if people don't check, you can get some really bizzare errors on things such as cgi's with apache.

      I saw code that never hit the alarm 0 'cause the eval died (no, not die()) on a particular line, and bailed on the eval, causing processing to die randomly due to the alarm never being reset :)

Re: Timeouts when reading from socket Filehandles?
by gmpassos (Priest) on Aug 28, 2002 at 17:57 UTC
    You probably need to use IO::Select, and the alarm too. Take a look in this example for select, to see how to use it. This example show how to read in the same time 2 sockets, without stop another:
    #!/usr/bin/perl ## Open the 2 socket connections: my $sock1 = new IO::Socket::INET( PeerAddr => host1 , PeerPort => 6622 , Proto => 'tcp', Timeout => 30) ; my $sock2 = new IO::Socket::INET( PeerAddr => host2 , PeerPort => 6622 , Proto => 'tcp', Timeout => 30) ; ## Crete the interface for select, with the 2 sockets: my $can_read = IO::Select->new( $sock1 , $sock2 ); ## File to log the data: open (LOG,"./log.txt") ; ## Here the select interface will return to the array ## @has_buf the $sockets with data in the buffer, using ## 1s of delay: while( my @has_buf = $can_read->can_read(1) ) { foreach my $has_buf_i ( @has_buf ) { ## $has_buf_i is one of the + sockets my $buffer ; ## Create another select to can read byte by byte, because ## we just know that the socket have data, but not the length: my $sel = IO::Select->new($has_buf_i) ; ## Read byte by byte: while( $sel->can_read(0.1) ) { sysread($has_buf_i, $buffer , 1 , length($buffer) ) ; } ## Print to the log file: if ($buffer ne '') { print LOG $buffer ;} } } exit;
    "The creativity is the expression of the liberty".
Re: Timeouts when reading from socket Filehandles?
by Jeppe (Monk) on Aug 27, 2002 at 19:31 UTC
    Although I don't have the time (or memory) to give you code, you should look into the whole non-blocking I/O beastiary. When you get down to it, non-blocking I/O is simply the ability to check for new data / write new data without having to wait for the operation to finish. That is exactly what you want.
Re: Timeouts when reading from socket Filehandles?
by Anonymous Monk on Aug 28, 2002 at 22:52 UTC
    You need to use the select() statement. Look in the man pages for an example.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (4)
As of 2024-03-29 07:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found