eibwen has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to create a simple wrapper to make console programs accessible with sockets.

Input from the client is being received by the wrapper and successfully forwarded to the program; however the output from the program is NOT being received by the wrapper, and consequently cannot be forwarded to the client.

This would seem to suggest a problem related to open2; however the error-checking in the IPC::Open2 perldoc indicates that the program is being run successfully, as confirmed by output from a test program. Consequently, I can only surmise that select is not identifying when there is data to be read on the $output filehandle...

UPDATE: I tried writing a test program with autoflush, but it didn't seem to work. Adding an iterative print with a very short delay got the output from the program to be received by the wrapper, which was then successfully forwarded to the client. Now I've just got to figure out how to either turn off buffering, or preferably set per line buffering. This is discussed to an extent in the "Bidirectional Communication with Another Process" section of the perlipc perldoc, but I've yet to figure out how to implement it for this application...

Code for the wrapper follows:

#!/usr/bin/perl use IPC::Open2; use IO::Socket; my $server = IO::Socket::INET->new( LocalPort => 8000, Listen => 1, Reuse => 1, Proto => 'tcp' ) or die $@; my $client = $server->accept; my ($output, $input); my $pid = open2($output, $input, '/usr/bin/bc'); my $length = 80; my $readable; vec($readable, fileno($output), 1) = 1; vec($readable, fileno($client), 1) = 1; while (select($readable, undef, undef, undef)) { if (vec($readable, fileno($output), 1)) { my $data; sysread $output, $data, $length; # Read + output from program syswrite $client, $data; # Forw +ard to client print 'PROGRAM:', "\t", $data; } if (vec($readable, fileno($client), 1)) { my $data; sysread $client, $data, $length; # Read + input from client syswrite $input, $data; # Forw +ard to program print 'CLIENT:', "\t", $data; } unless ($server and $client and $input and $output) { close $_ for $input, $output, $client, $server; # Exit + if program handles closed waitpid $pid, 0; exit; } }

Replies are listed 'Best First'.
Re: select open2 filehandles for reading
by sgifford (Prior) on Apr 30, 2007 at 15:57 UTC
    The traditional UNIX way to determine whether to use line- or block-buffering (and the way generally implemented by the stdio library) is by whether stdout is connected to a terminal (TTY) or not. You can convince many programs to use line buffering by connecting them to a pseudo-TTY, using a module like IO::Pty or Expect.
Re: select open2 filehandles for reading
by dk (Chaplain) on Apr 30, 2007 at 17:27 UTC
    If you're not catching output of the program, you don't need open2, just open F, "|bc" will be enough. You also probably want your sockets and pipes to be non-blocking, so the program won't wait until all 80 bytes are entered. I understand you probably want to hack it all by yourself without extra modules (I definitely would), but if not, you might look into f.ex. IO::Events (excuse me for the shameless plug, but I myself like to hack non-blocking IO), where by a strange coincidence the example code in synopsis also wraps bc. Alternatively, IO::Select or even POE might be of interest.