Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

use sysread to read non-blocking filehandle

by x12345 (Novice)
on Nov 04, 2014 at 12:43 UTC ( #1106019=perlquestion: print w/replies, xml ) Need Help??

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

Hello, the experts:
According to someone's code, I try to reproduce the following: open a filehandle to run a command in remote linux machine, set it to non-blocking filehand, then use a sysread loop to read the results from the filehandle. It does't work. Could you help me check what is wrong in my code :

my $cmd = '/opt/rssh/bin/ssh'; my $machine = "remote_machine"; open(my $fh, "-|", "$cmd $machine \"hostname;uptime\" 2>&1") or die "c +annot open fh"; my $flags = fcntl($fh, F_GETFL, 0) or die "\ncan't get flags for the p +ipe: $!\n"; fcntl($fh, F_SETFL, $flags | O_NONBLOCK) or die "\ncan't set flags: $! +\n"; my $out = $fh; my $bytes_read = -1; my $blocksize = 1024; my $result = ""; while ($bytes_read) { my $buf; $bytes_read = sysread($out, $buf, $blocksize); if (defined($bytes_read)) { if ($bytes_read == 0) { close($out); last; } else { print "\nbuf content\n"; $result.= $buf; } }else { if ($! == EAGAIN()) { print "\nEAGAIN is set\n"; last; } else { last; } } } print "\nresult is: $result \n";
The result is:
EAGAIN is set result is:
But if I replace the "while ($bytes_read) " with the while (<$fl>) as the following, I can get the result.
my $cmd = '/opt/rssh/bin/ssh'; my $machine = "remote_machine"; open(my $fh, "-|", "$cmd $machine \"hostname;uptime\" 2>&1") or die "c +annot open fh"; #my $flags = fcntl($fh, F_GETFL, 0) or die "\ncan't get flags for the +pipe: $!\n"; #fcntl($fh, F_SETFL, $flags | O_NONBLOCK) or die "\ncan't set flags: $ +!\n"; my @result ; while (<$fh>) { # chomp; push @result,$_; } print "\nresult is: @result \n";

The result is
result is: ccwsge0553 13:40:10 up 4 days, 2 min, 0 users, load average: 0.08, 0.03, 0.01
What is wrong in my code with non-blocking/sysread? Thanks in advance!

Replies are listed 'Best First'.
Re: use sysread to read non-blocking filehandle
by Corion (Pope) on Nov 04, 2014 at 12:56 UTC
    while ($bytes_read) { my $buf; $bytes_read = sysread($out, $buf, $blocksize); ...

    Your code leaves the loop as soon as there is nothing to read on a socket.

    while( <$fh> ) will read things until it encounters a newline.

      If there is nothing to read,it means the sysread has finished all the reading, I should see something in the results?

        x12345:

        Not exactly--it can also mean "I haven't received a response yet". So you're probably terminating the loop before the other side ever had a chance to reply. (Considering the timing, you may be exiting before the other computer even received the request.)

        Update: It can also mean "The network is really busy, so the next packet hasn't arrived yet." That could be a problem if you've received only part of your response.

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

        If there is nothing to read,it means the sysread has finished all the reading?

        Or an error. You got error EAGAIN. That error signifies that sysread should block, but the file handle is non-blocking.

        EAGAIN or EWOULDBLOCK: The file descriptor fd refers to a socket and has been marked nonblocking (O_NON-BLOCK), and the write would block. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.

        What you want:

        my $buf; while (1) { my $rv = sysread($out, $buf, 64*1024, length($buf)); if (!defined($rv) && !$!{EAGAIN} && !$!{EWOULDBLOCK}) { die $!; } if (defined($rv) && !$rv) { last; } ... whatever it is you wanted to do instead of blocking ... } print $buf;
        I found the problem in my loop, after use perl -d debugger, it is the $bytes_read should be "my $bytes_read", in the code, it is defined twice, it is a little bit confused, should have better clear way to do that, but in the code I have, it is like that, and when I rewrite the code, I remove my in frond $bytes_code in the while loop, which was wrong. So it should be
        my $bytes_read = sysread($fh,$bug,$blocksize)
Re: use sysread to read non-blocking filehandle
by MidLifeXis (Monsignor) on Nov 04, 2014 at 14:52 UTC

    When you get EAGAIN, why are you exiting the loop? That indicator tells you that you should try another read, probably after a small delay -- basically you have not received any new data to read. Adjust that portion of code (don't call last) and your termination test in the while loop and you should see different results.

    Ref: sysread, What does eagain mean (SO)

    --MidLifeXis

Re: use sysread to read non-blocking filehandle
by RichardK (Parson) on Nov 04, 2014 at 13:03 UTC

    Two calls to last doesn't look right. Maybe one of these should be a next?

    if ($! == EAGAIN()) { print "\nEAGAIN is set\n"; last; } else { last; }
      If there are severals filehandles parallel at the same time, I can do a loop and next to read the filehandels. Here I just use a simple example to try non-blocking and sysread. So just one filehandle, set to non blocking, then read.
        If I just use once sysread to try, it is still empty. Here is the code, what is wrong in the code?
        my $cmd = '/opt/rssh/bin/ssh'; my $machine = "remote_machine"; open(my $fh, "-|", "$cmd $machine \"hostname;sleep 5;uptime\" 2>&1") o +r die "cannot open fh"; my $flags = fcntl($fh, F_GETFL, 0) or die "\ncan't get flags for the p +ipe: $!\n"; fcntl($fh, F_SETFL, $flags | O_NONBLOCK) or die "\ncan't set flags: $! +\n"; my $out = $fh; my $bytes_read = -1; my $blocksize = 1024; my $result = ""; my $buf; $bytes_read = sysread($out, $buf, $blocksize); print "\nl buf content is:\n $buf \n"; close $out;

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (8)
As of 2019-12-09 12:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?