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

I'm trying to write a network connecticity application that has, as one of the functions, the ability to run a console application with bidirectional data across a socket, much like having a forwarded interactive console.

This is ActiveState perl 5.8.8.816. This will be compiled with the PDK, so if it's possible to do this with very few modules, I'm all for it.

Of course, there are other things I want to do with this or I would simply use existing tools, but this is the piece that's breaking.
First, I thought I might be able to use
open2($socket,$socket, "cmd.exe");
And Select on the $output and network socket, waiting for an error. I _hoped_ this would dup the socket and Just Work. This, of course, didn't work, or I wouldn't be posting here.
Then I tried a few other ideas:
if (my $client = $server->accept( )) { open2($output,$input, "cmd /k"); $select->add($client); $select->add($output); } while(1) { foreach my $current_socket($select->can_read()) { my $data; $current_socket->read($data, 10,0); die unless $data; print $data, "\n"; } }
Which doesn't work, because select always returns an empty list.

Then I tried:
my $select = IO::Select->new( ); if (my $client = $server->accept( )) { open3($input,$output, undef, "cmd.exe"); $select->add($client); } $output->blocking(0); #fcntl($output, F_SETFL(), O_NONBLOCK()); while(1) { foreach( my ($current_socket) = $select->can_read(.5)) { last unless $current_socket; my $data; $current_socket->sysread($data,10,0); die unless $data; print $data, "\n"; } #we hit the timeout, so check the terminal for new data $output->sysread($data, 10, 0); print $data, "\n"; }
Which I had hoped would at least print both streams. $output blocks, though, cannot be selected on, and, as far as I can tell, cannot be modified by FCntl to set it to non-blocking.

Any thoughts on what I can do from here to hopefully get this working?

Replies are listed 'Best First'.
Re: Win32 console polling
by salva (Canon) on Mar 29, 2006 at 13:26 UTC
    On Windows, select is only supported for sockets (it's not perl fault but a limitation of the crappy OS).

    Some days ago, to solve a similar problem (Windows, pipes and multiplexing IO), I created Win32::Socketpair, a module that emulates socketpair with TCP socket connections going through the localhost interface. For instance:

    use Win32::Socketpair 'winopen2'; my ($pid, $socket) = winopen2(@cmd) or die "unable to run command @cmd"; my $fno = fileno $socket; my $v = ''; vec($v, $fno, 1) = 1; while(1) { my $vin = $v; my $vout = length $data ? $v : ''; if (select($vin, $vout, undef, undef)>0) { if (vec($vin, $fno, 1)) { sysread($socket, my $buffer, 2000) or last # closed } if (vec($vout, $fno, 1)) { syswrite($socket, $data) or last # closed } } }

    You can also use pipes created this way with IO::Select.

    I believe that setting the socket to non-blocking is not needed if you are going to use it exclusively inside a select loop, but anyway, on Windows to set non-blocking mode for a socket you have to use this code:

    ioctl($socket, 0x8004667e, 1);
    Non-blocking socket read on Windows contains more information on the matter and links to other related nodes.
      Thanks.

      I'm going to take a look at that module and see if it works for what I need. Using loopback and sockets had not occurred to me.

      It's not the socket blocking I'm worried about, but the PIPE I was using from open2. I guessed that the problem was that select in windows only works on sockets, but you can supposedly use WaitForMultipleObjectEx and some of the other winsock functionality to create a select that actually works on any signalable object. I've even been considering writing a module to that effect in C.