I have a C program that simply runs a loop that reads a JSON structure from STDIN and writes a line to STDOUT.
In order to support a variety of front-end formats, I want to write a Perl program that repeatedly reads data, converts it to JSON, submits it to the C program, and receives the output -- as if I were using qx//
to invoke the C program, only without launching it afresh each time.
This thread describes the same problem, except the parent process is in C. I wondered whether Perl provided a way to do this more easily. It would be preferable (but not essential) for the C program to stay the same and be unaware whether it was forked by Perl or run from the command line, if possible.
To illustrate (note - using Perl for the child, but hopefully the same principles apply):
File parent.pl
#!/usr/bin/env perl
use warnings;
use strict;
$|++;
# {{ spawn child.pl }}
while (1) {
print "Enter text to send to the child: ";
my $text = <>;
last if !defined $text;
# {{ send $text on some file descriptor to child.pl }}
# {{ receive $reply on some file descriptor from child.pl }}
}
File child.pl
:
#!/usr/bin/env perl
use warnings;
use strict;
$|++;
while (my $line = <STDIN>) {
chomp $line;
$line .= ", back atcha.\n";
print $line;
}
Execution:
$ parent.pl
Enter text to send to the child: hello
hello, back atcha.
Enter text to send to the child:
UPDATE:
The caveats for using open2
, stated both by @ikegami below and in Programming Perl / Interprocess Communication, don't seem to me to apply here, given:
open3
and select
) Given these conditions from the original question ...
... the following will work. (Note that the child is written here in Perl but could also be C.)
parent.pl
#!/usr/bin/env perl
use warnings;
use strict;
use IPC::Open2;
$|=1;
my $pid = open2(my $ifh, my $ofh, 'child.pl') or die;
while (1) {
print STDOUT "Enter text to send to the child: ";
my $message = <STDIN>;
last if !defined $message;
print $ofh $message; # comes with \n
my $reply = <$ifh>;
print STDOUT $reply;
}
close $ifh or die;
close $ofh or die;
waitpid $pid, 0;
child.pl
#!/usr/bin/env perl
use warnings;
use strict;
$|=1;
while (my $line = <STDIN>) {
chomp $line;
print STDOUT $line . ", back atcha.\n";
}