in reply to Re: blocking, non-blocking, and semi-blocking
in thread blocking, non-blocking, and semi-blocking

Thanks for all your replies. I was able to get it implemented using sfink's /bin/tail trick:

(No, not quite. See my follow up post below.)

#!/usr/bin/perl use IO::Select; use IO::Socket; use POSIX; local $| = 1; $timeout = 0.1; #### setup the file.... open $tail, "/usr/bin/tail -f -n 0 /tmp/test_file |"; my $rin = ''; vec($rin, fileno($tail), 1) = 1; fcntl($tail, F_SETFL(), O_NONBLOCK()); ###### setup the socket.... $main_sock = new IO::Socket::INET ( LocalHost => 'localhost', LocalPort => 4321, Listen => 5, Proto => 'tcp', ReuseAddr => 1, ); $readable_handles = new IO::Select(); $readable_handles->add($main_sock); while (1) { ######### do tail stuff here... print "selecting\n"; $nfound = select($rout = $rin, undef, undef, $timeout); while ($ret = sysread $tail, $buf, 1024) { print $count++," $buf\n"; } ######### do TCP socket stuff.... print "checking sockets\n"; ($new_readable) = IO::Select->select($readable_handles, undef, undef, $timeout); foreach $sock (@$new_readable) { if ($sock == $main_sock) { print "new connection\n"; $new_sock = $sock->accept(); $readable_handles->add($new_sock); } else { print "reading socket\n"; while ($ret = sysread $sock, $buf, 1024) { print $count++, " $buf\n"; } print "closing socket\n"; $readable_handles->remove($sock); close $sock; } } }

Replies are listed 'Best First'.
Re^3: blocking, non-blocking, and semi-blocking
by genecutl (Beadle) on Aug 30, 2004 at 16:06 UTC
    Actually, it turns out that didn't work. The file tail pipe would stop working with `ps` showing "tail [defunct]". I tried closing that pipe and then opening a new one when the sysread returned undef, but the new pipe wouldn't give me any output. I found another file tailing trick in the Perl Cookbook which now verifiably works for me. Here is the code:
    use IO::Select; use IO::Socket; use POSIX; ##### setup the file.... # open it open my $tail, $FILE or die $!; # set to non-blocking fcntl( $tail, F_SETFL(), O_NONBLOCK() ); # [ fill up the file info buffer ] ###### setup the socket.... + $main_sock; $readable_handles; $main_sock = new IO::Socket::INET( LocalHost => 'localhost', LocalPort => $PORT, Listen => 8, Proto => 'tcp', ReuseAddr => 1, ); $readable_handles = new IO::Select(); $readable_handles->add($main_sock); while (1) { ######### do file tail stuff here... + # unset the EOF (as seen in Perl Cookbook) $tail->clearerr(); # read any new lines if ( @lines = (<$tail>) ) { # [ add @lines to buffer ] # [ discard old lines from buffer ] # [ other processing of data... ] } ######### do TCP socket stuff.... + ($new_readable) = IO::Select->select( $readable_handles, undef, un +def, $TIMEOUT ); foreach my $sock (@$new_readable) { if ( $sock == $main_sock ) { $new_sock = $sock->accept(); $new_sock->autoflush(1); $readable_handles->add($new_sock); } else { if ( $ret = sysread $sock, $buf, 4 ) { # [ process the received info, generate $reply ] # reply to the client + print $sock $reply; } # close the client + $readable_handles->remove($sock); close $sock; } } }
Re^3: blocking, non-blocking, and semi-blocking
by sfink (Deacon) on Aug 31, 2004 at 04:32 UTC
    I can't explain the behavior you're observing, but the code you posted is incorrect. You are separating out the two selects, which means it won't check for socket output until it gets tail output, and once it does, it won't check for tail output until it gets socket output. You need to combine them together, and when select returns you have to figure out whether it's the pipe from tail or the socket that has data available.

    As for the problem of your tail dying, I suggest you sprinkle salt on it once a week and be careful how you sit down. No, wait, that's wrong. I meant to say that I suspect the tail would fail even if you ran it from the command line -- either because that file doesn't exist, or because your version of tail doesn't support the command-line arguments you're passing it. If you want to tail -f a file that might not exist yet, use tail -F (for GNU tail, at least). If I'm wrong and the cause of death is more mysterious, try either changing "tail -f -n 0 /tmp/test_file |" to "tail -f -n 0 /tmp/test_file 2>&1 | tee /tmp/unhappy.log |", or to "strace -o /tmp/unhappier.log tail -f -n 0 /tmp/test_file". Examine the generated log file to diagnose the problem.

    Once you merge the two selects, you can dispense with the timeout too.

      The code does work, it's running right now. This line:

      fcntl( $tail, F_SETFL(), O_NONBLOCK() );

      sets the file to non-blocking. When the code gets to

      if ( @lines = (<$tail>) ) {

      It skips right by if nothing new has been added to the file. In fact, the fcntl statement might not be needed, because this line reads to the current EOF and then continues. The clearerr statement resets the EOF each time around so that the file can be tailed.

      The select statement:

       ($new_readable) = IO::Select->select( $readable_handles, undef, undef, $TIMEOUT );

      times out when no-one is connecting. I'm setting $TIMEOUT to 0.25 seconds. It will only block for that long, before continuing around the loop back to the file read. I'm using 0.25 as a compromise between availability and CPU usage.