4

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:

  • I don't care about STDERR (which would require open3 and select)
  • I control the child source code and can therefore guarantee that autoflushing occurs.
  • The protocol is strictly send one line, receive one line.
2
  • How do you demote the end of a request? How do you denote the end of a response? Is the child's output truly unbuffered? Commented Apr 14, 2018 at 2:29
  • Both the request and the response are one "line" of text terminated by \n. And doesn't $|++ guarantee that the child's newline-terminated line will get flushed? Commented Apr 14, 2018 at 3:04

1 Answer 1

3

Given these conditions from the original question ...

  • You don't care about reading STDERR
  • You control the child source code and can therefore guarantee that autoflushing occurs.
  • The protocol is strictly send one line, receive one line.

... 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"; } 
Sign up to request clarification or add additional context in comments.

1 Comment

Yeah, that works. Just make sure not to send another request before receiving the response of the previous one.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.