Bidirectional Communication with Another Process |
While this works reasonably well for unidirectional communication, what about bidirectional communication? The obvious thing you'd like to do doesn't actually work:
open(PROG_FOR_READING_AND_WRITING, "| some program |")
and if you forget to use the use warnings
pragma or the -w flag,
then you'll miss out entirely on the diagnostic message:
Can't do bidirectional pipe at -e line 1.
If you really want to, you can use the standard open2()
library function
to catch both ends. There's also an open3()
for tridirectional I/O so you
can also catch your child's STDERR, but doing so would then require an
awkward select()
loop and wouldn't allow you to use normal Perl input
operations.
If you look at its source, you'll see that open2()
uses low-level
primitives like Unix pipe()
and exec()
calls to create all the connections.
While it might have been slightly more efficient by using socketpair(), it
would have then been even less portable than it already is. The open2()
and open3()
functions are unlikely to work anywhere except on a Unix
system or some other one purporting to be POSIX compliant.
Here's an example of using open2():
use FileHandle; use IPC::Open2; $pid = open2(*Reader, *Writer, "cat -u -n" ); print Writer "stuff\n"; $got = <Reader>;
The problem with this is that Unix buffering is really going to
ruin your day. Even though your Writer
filehandle is auto-flushed,
and the process on the other end will get your data in a timely manner,
you can't usually do anything to force it to give it back to you
in a similarly quick fashion. In this case, we could, because we
gave cat a -u flag to make it unbuffered. But very few Unix
commands are designed to operate over pipes, so this seldom works
unless you yourself wrote the program on the other end of the
double-ended pipe.
A solution to this is the nonstandard Comm.pl library. It uses pseudo-ttys to make your program behave more reasonably:
require 'Comm.pl'; $ph = open_proc('cat -n'); for (1..10) { print $ph "a line\n"; print "got back ", scalar <$ph>; }
This way you don't have to have control over the source code of the
program you're using. The Comm library also has expect()
and interact()
functions. Find the library (and we hope its
successor IPC::Chat) at your nearest CPAN archive as detailed
in the SEE ALSO section below.
The newer Expect.pm module from CPAN also addresses this kind of thing. This module requires two other modules from CPAN: IO::Pty and IO::Stty. It sets up a pseudo-terminal to interact with programs that insist on using talking to the terminal device driver. If your system is amongst those supported, this may be your best bet.
Bidirectional Communication with Another Process |