Nonblocking Pipe Open

G

Gregory Toomey

I need to combine pipe open + make it non-blocking. The semantics I want
are:

# based on perlopentut
open(NET, "ping 11.22.33.44 |", O_NONBLOCK ) || die "can't fork ping";
while (<NET>) { print }
close(NET)

which of course gets a syntax error.
Any idea how to achieve this?

gtoomey
 
J

J. Romano

Gregory Toomey said:
I need to combine pipe open + make it non-blocking. The semantics I want
are:

# based on perlopentut
open(NET, "ping 11.22.33.44 |", O_NONBLOCK ) || die "can't fork ping";
while (<NET>) { print }
close(NET)

which of course gets a syntax error.
Any idea how to achieve this?


Dear Greg,

To be able to read a command's output in a non-blocking manner, you
can use the IPC::Open2 module together with IO::Select. Here is a
sample program that pings 127.0.0.1:


#!/usr/bin/perl -w

use strict;
use IPC::Open2;
use IO::Select;
$| = 1; # autoflush STDOUT

# Declare filehandles and command to use:
my ($r, $w);
my $cmd = 'ping 127.0.0.1';

# Open the process and set the selector:
my $pid = open2($r, $w, $cmd);
my $selector = IO::Select->new($r);

sleep 1; # allow some time for request to process

# print out output from process, if any exists:
while ($selector->can_read(0))
{
my $char;
sysread($r, $char, 1);
print $char;

unless ($selector->can_read(0))
{
sleep 1; # allow some time for request to process
# or else while loop will finish if there
# there is a pause in the program
}
}

__END__


I basically use IO::Select with the can_read() method to tell when
output is waiting for me to read. Note that I periodically sleep for
some time in order to give the process enough time to output some
text. Without the sleep command, the while loop would exit as soon as
ping produces a pause (because technically there is nothing waiting to
be read during a pause).

This script should work on Unix, but I'm almost entirely sure it
won't work on Win32 platforms.

Hope this helps,

-- Jean-Luc
 
G

Gregory Toomey

J. Romano said:
Dear Greg,

To be able to read a command's output in a non-blocking manner, you
can use the IPC::Open2 module together with IO::Select. Here is a
sample program that pings 127.0.0.1:


#!/usr/bin/perl -w

use strict;
use IPC::Open2;
use IO::Select;
$| = 1; # autoflush STDOUT

# Declare filehandles and command to use:
my ($r, $w);
my $cmd = 'ping 127.0.0.1';

# Open the process and set the selector:
my $pid = open2($r, $w, $cmd);
my $selector = IO::Select->new($r);

sleep 1; # allow some time for request to process

# print out output from process, if any exists:
while ($selector->can_read(0))
{
my $char;
sysread($r, $char, 1);
print $char;

unless ($selector->can_read(0))
{
sleep 1; # allow some time for request to process
# or else while loop will finish if there
# there is a pause in the program
}
}

__END__


I basically use IO::Select with the can_read() method to tell when
output is waiting for me to read. Note that I periodically sleep for
some time in order to give the process enough time to output some
text. Without the sleep command, the while loop would exit as soon as
ping produces a pause (because technically there is nothing waiting to
be read during a pause).

This script should work on Unix, but I'm almost entirely sure it
won't work on Win32 platforms.

Hope this helps,

-- Jean-Luc


I'll give it a try.

I'm looking at writing a "domain diagnoser" that
- does whois, dig & ping concurrently for a domain (& subdomains)
- interprets data from the subprocesses & and displays results in real time
- possibly uses an expert system to diagnose problems

gtoomey
 
R

Rocco Caputo

I'm looking at writing a "domain diagnoser" that
- does whois, dig & ping concurrently for a domain (& subdomains)
- interprets data from the subprocesses & and displays results in real time
- possibly uses an expert system to diagnose problems

You may want to consider using POE instead of IO::Select if you plan to
do more complex things. For example, it can help you avoid rewriting
an IO::Select loop if you choose to add a graphical interface later.

http://poe.perl.org/?POE_Cookbook has several examples, including
pinging multiple hosts, working with graphical interfaces, and managing
child processes.

http://poe.perl.org/?Poing has a program I wrote several years ago.
It's a multi-host ICMP pinger with response history. I run it around
the clock to keep tabs on my internet provider. You should see some of
the old screen shots.

By the way, I'm POE's principal author.
Here's your obligatory grain of salt. :)
 
J

J. Romano

Dear Gregory,

Just after I posted my sample Perl script, I realized that I could
write the same loop without sleep calls if I just use an inifnite loop
to continually check to see if there is output waiting to be read. In
other words, here's a script that does the same thing as the one I
gave you yesterday, but without sleeping:


#!/usr/bin/perl -w

use strict;
use IPC::Open2;
use IO::Select;
$| = 1; # autoflush STDOUT

# Declare filehandles and command to use:
my ($r, $w);
my $cmd = 'ping 127.0.0.1';

# Open the process and set the selector:
my $pid = open2($r, $w, $cmd);
my $selector = IO::Select->new($r);

while (1) # infinite loop (use "last" to break out)
{
if ($selector->can_read(0))
{
my $char;
sysread($r, $char, 1);
print $char;
}

# Do anything you want in between reads here...
}

__END__


The advantage to this script is that, if your commands (like
"whois", "dig", and "ping") happen to pause, the loop won't
automatically break out. The disadvantage to this script is that it
might be difficult figuring out when a command has finished, or just
has delayed output (in which case you might have to put in a few
sleep() calls). Either way, I think that this script here does a
better job of helping you visualize what is going on -- you just need
to be mindful of the fact that some programs don't flush their output
right away, and that it's not a simple matter to tell if the program
has stopped running altogether.

So you might want to give the above script a try, if my first was
too confusing. But if both are too overwhelming for you, you might
want to check out Rocco Caputo's solution.

Hopefully one of our solutions will help.

-- Jean-Luc
 
J

Joe Smith

Gregory said:
# based on perlopentut
open(NET, "ping 11.22.33.44 |", O_NONBLOCK ) || die "can't fork ping";

You need to read perlopentut again. It clearly shows that O_NONBLOCK is
to be used with sysopen(), not with open().
-Joe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top