problem writing to stdin of child process

J

john

Hello everyone,

I have a program which forks multiple children and needs to have
bidirectional communication with each child. Each child needs to use
STDIN and STDOUT to talk back to the parent.

The problem is that I'm having trouble connecting the pipe to STDIN of
the child. I've tried various approaches. A simple testcase is below.
In this case, the child seems to read the number (I think) of the pipe
file descriptor rather than the string I send down the pipe.

perl -v shows...
This is perl, v5.8.2 built for aix-thread-multi

Can anyone tell me where I'm going wrong ?
Thanks in advance.



#!/usr/bin/perl
use strict;
use warnings;

use IO::Handle;
use IO::pipe;

my $cr = IO::Handle->new(); # child reader
my $pw = IO::Handle->new(); # child writer

new IO::pipe($cr, $pw) or die 'pr/cw pipe';

my $pid = fork();
if ($pid > 0) {

# Parent

print {$pw} "hello!\n"; # sending to the child
close($pw);

} else {
# Child

# Connect stdin to pipe

close($pw);
my $fd = fileno($cr);
open(my $stdin, "<", \$fd) or die "STDIN open: $!";
*STDIN = $stdin;

my $line = <STDIN>; # hopefully reading from the parent
chomp $line;
print "child received: ($line)\n";
close($cr);
exit(0);
}

wait;
 
B

Big and Blue

john said:
#!/usr/bin/perl
use strict;
use warnings;

use IO::Handle;
use IO::pipe;

my $cr = IO::Handle->new(); # child reader
my $pw = IO::Handle->new(); # child writer

new IO::pipe($cr, $pw) or die 'pr/cw pipe';

Have you read the IO::pipe documentation?
(e.g. http://search.cpan.org/~nwclark/perl-5.8.6/ext/IO/lib/IO/Pipe.pm)

It starts with (almost) exactly what you want under the SYNOPSIS. (It
has the child writing to the parent - just swap the if/else codew blocks).

No need to mention IO::Handle (IO::pipe gets them for you).

my $fd = fileno($cr);
open(my $stdin, "<", \$fd) or die "STDIN open: $!";
*STDIN = $stdin;

my $line = <STDIN>; # hopefully reading from the parent

Not sure why you would want to do this anyway. You shouldn't be
reading from STDIN - you want to read from the read-side of the pipe opened
in the parent. Don't assume that just because your want to read from it
you have to make it STDIN. STDIN is "STanDard INput" - reading from a pipe
isn't "standard" in this sense.
 
J

john

Big and Blue said:
Have you read the IO::pipe documentation?
(e.g. http://search.cpan.org/~nwclark/perl-5.8.6/ext/IO/lib/IO/Pipe.pm)

It starts with (almost) exactly what you want under the SYNOPSIS. (It
has the child writing to the parent - just swap the if/else codew blocks).

I've seen this on my travels, but for some reason it didn't sink in
that this was what I needed. Terms such as "re-blessed" confuse me and
I've been sticking to stuff that I *thought* I understood. Anyway
you're right. This is exactly what I need and it'll make my code a lot
neater. I was going to post the modified and working testcase, however
it's so close to the example in the IO:pipe doc that there doesn't
seem much point.
No need to mention IO::Handle (IO::pipe gets them for you).

I'm using autoflush in my larger program, but you're right; it's not
needed in this testcase.
Not sure why you would want to do this anyway. You shouldn't be
reading from STDIN - you want to read from the read-side of the pipe opened
in the parent. Don't assume that just because your want to read from it
you have to make it STDIN. STDIN is "STanDard INput" - reading from a pipe
isn't "standard" in this sense.

The children will each exec an external command which will read from
stdin, and the parent has to manage sending data to each.

Thanks for your help "Big and Blue".
 
A

Anno Siegel

john said:
Hello everyone,

I have a program which forks multiple children and needs to have
bidirectional communication with each child. Each child needs to use
STDIN and STDOUT to talk back to the parent.

Have you considered IPC::Open2?

Anno
 
J

john

I've seen this on my travels, but for some reason it didn't sink in
that this was what I needed. Terms such as "re-blessed" confuse me and
I've been sticking to stuff that I *thought* I understood. Anyway
you're right. This is exactly what I need and it'll make my code a lot
neater. I was going to post the modified and working testcase, however
it's so close to the example in the IO:pipe doc that there doesn't
seem much point.


I'm using autoflush in my larger program, but you're right; it's not
needed in this testcase.


The children will each exec an external command which will read from
stdin, and the parent has to manage sending data to each.

Thanks for your help "Big and Blue".


Sorry, I spoke too soon. I'm still left with my original problem of
how to attach the pipe to STDIN of the child. The various approaches
I've tried either raise an invalid argument error or the child appears
to read the number of the file descriptor rather than the data.
 
J

john

Have you considered IPC::Open2?

Anno

This is close to what I want because it connects the reader and writer
filehandles to STDIN and STDOUT of the child, however I wanted to
control the exec of the child myself, so that I could have a test
harness within the same program file which simulates the child
behaviour.

I still don't understand why what I'm trying to do doesn't work but if
no-one has any better ideas I'll try with IPC::Open2 (or maybe Open3
if I need STDERR) as suggested.

Thanks for tip.
 
B

Big and Blue

john said:
Sorry, I spoke too soon. I'm still left with my original problem of
how to attach the pipe to STDIN of the child. The various approaches
I've tried either raise an invalid argument error or the child appears
to read the number of the file descriptor rather than the data.

Hav a look at the documentation for open. It gives (or gave...) an
example of saving STDOUT and STDERR, opening somethign else on them and
then restoring the original.

Rearrange as appropriate for STDIN.
 
J

john

Big and Blue said:
Hav a look at the documentation for open. It gives (or gave...) an
example of saving STDOUT and STDERR, opening somethign else on them and
then restoring the original.

Rearrange as appropriate for STDIN.

Once again, I may be speaking too soon...
It's not obvious from the perdoc, but the following seems to work with
the IO::pipe version of the testcase...

my $fd = fileno($pipe);
open(STDIN, "<&$fd") or die "STDIN open: $!";

I'll plug this back into my original program and see if it keeps
working :)
Thanks for your help.

Here's the modified code...

#!/usr/bin/perl
use strict;
use warnings;

use IO::pipe;

my $pipe = new IO::pipe or die 'pipe';

my $pid = fork();
if ($pid > 0) {

# Parent
$pipe->writer();

print $pipe "hello!\n"; # to the child
close($pipe);

} else {
# Child

# Connect stdin to pipe

$pipe->reader();

my $fd = fileno($pipe);
open(STDIN, "<&$fd") or die "STDIN open: $!";

my $line = <STDIN>; # from the pipe ?
chomp $line;
print "child received: ($line)\n";
close($pipe);
exit(0);
}

wait;
 

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

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top