Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

stdin-socket without fork()??

by gharris (Beadle)
on Nov 09, 2000 at 01:23 UTC ( #40632=perlquestion: print w/replies, xml ) Need Help??
gharris has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to create a script that will route data to/from stdin/out and a socket, without using fork() (Though there is preliminary support for fork() in the latest ActivePerl, I would rather avoid that route.)
I got select (IO::Select actually) to work great using two sockets, but select doesnt seem to like filehandles. So I tried this:
while ( sysread(STDIN, $buf, 1024) ) || ( @ready = $sel->can_read() )
but that just blocks on the sysread(STDIN...
I thought about using the timeout option, but I don't want the script to pause in either direction.
The end purpose for this script is to establish a connection for ssh (as the ProxyCommand). I am adapting a script written by Simon Josefsson to work on Windows NT.
Thanks for any help,
Glenn Harris

Replies are listed 'Best First'.
Re: stdin-socket without fork()??
by Fastolfe (Vicar) on Nov 09, 2000 at 01:26 UTC
    You need to add STDIN and STDOUT to your $sel IO::Socket object and treat it like any other. If anything is available for reading, add it to the write queue for the other. If anything's in the write queue and the file handle is available for writing, write it.

    Without selecting first (like you're doing implicitely via $sel->can_read), a sysread call will block until data is available to be read.

    You may be interested in setting $|=1 (or doing $filehandle->autoflush), to keep stdio buffering from slowing you up.

      That was how I wrote the first incarnation (I think at least).
      I am not polling for writable handles because in my previous experiences that was mostly unnecessary.
      The while loop exits immediately with nothing in @ready. That problem led me to believe that IO::Select was not happy with filehandles. At any rate, here is the complete script:
      use IO::Socket; use IO::Select; use IO::Handle; use strict; use warnings; my ($stdin, $stdout); my ($t_conn, $t_addr, $t_port, $t_buf); my ($buf, @ready, $socket, $sel, $ret); $t_addr = shift; $t_port = shift; $stdin = new IO::Handle; $stdin->fdopen(fileno(STDIN), 'r') $stdout = new IO::Handle; $stdout->fdopen(fileno(STDOUT), 'w') $t_conn = IO::Socket::INET->new(PeerAddr => $t_addr, PeerPort => $t_port, Proto => 'tcp'); if ( $t_conn->connected() ) { print 'connected'."\n"; } else { die 'could not establish a connection...'."\n"; } $t_conn->syswrite('Connected!'."\n"); $sel = new IO::Select(); $sel->add($t_conn); $sel->add($stdin); $stdout->syswrite('begin transmissions...'."\n"); print $sel->count()."\n"; while ( ( $sel->count() > 0 ) && ( @ready = $sel->can_read() ) ) { if ( length($buf) > 0 ) { $t_conn->syswrite($buf); } foreach $socket (@ready) { if ( $socket == $t_conn ) { if ( $t_conn->connected() ) { if ( $t_conn->sysread($buf, 1024) > 0 ) { $stdout->syswrite($buf); } else { print 'lost connection to tunnel, shutting down... +'."\n"; $sel->remove($t_conn); $t_conn->close(); $stdin->close(); $stdout->close(); } } else { print 'lost connection to tunnel, shutting down...'."\ +n"; $sel->remove($t_conn); $t_conn->close(); $stdin->close(); $stdout->close(); } } elsif ( $socket == $stdin ) { if ( $stdin->opened() ) { if ( $stdin->sysread($buf, 1024) > 0 ) { $t_conn->syswrite($buf); } else { print 'lost connection to host, shutting down...'. +"\n"; $sel->remove($t_conn); $t_conn->close(); $stdin->close(); $stdout->close(); } } else { print 'lost connection to host, shutting down...'."\n" +; $sel->remove($t_conn); $t_conn->close(); $stdin->close(); $stdout->close(); } } } $buf = ''; } print 'all connections closed... exiting...'."\n@ready\n".$sel->handle +s()."\n";
      Well, I think I may have found my problem.
      I made a quick little script to test the basic select function call against STDIN:
      use strict; use warnings; my ($rin, $rout, $nfound); $rin = ''; vec($rin, fileno(STDIN), 1) = 1; $nfound = select($rout = $rin, undef, undef, 5); syswrite(STDOUT, "We stop here...\n");
      And I kept getting the same results, select returns immediately with nothing ready. So I decided that maybe it had something to do with the IO in the Windows NT console. So I copied that script over to my linux box (at home) and ran it there, and, well, it worked perfectly.
      Which means I wasn't going crazy (good thing), but that I might not be able to do what I want to do (bad thing).
      I did however write a very similar program in C that does work correctly, so I guess I will just have to write this in C.
      Thanks for your help, --Glenn
RE: stdin-socket without fork()??
by Anonymous Monk on Nov 09, 2000 at 21:17 UTC
    Select only supports sockets in ActivePerl. As far as I am aware there is no simple way to handle multiple IO under windows (apart from jumping to another language). Tim.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://40632]
Approved by root
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (2)
As of 2018-05-20 12:21 GMT
Find Nodes?
    Voting Booth?