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

Hello, im really stuck here and would be seriously greatfull for some help. Basically i need to use fork to do 3 things at the same time, usualy i can do this however what i am trying to do is to monitor the output of 2 connections and at the same time wait for input from the user, eg
while(<$telnet>){ print STDERR $_; };
and monitor another connection
while(<$telnet2>){ print STDERR $_; };
while at the same time monitoring input
while (<STDIN>){ print $_; };
Im having trouble monitoring the second connection, any help would be fantastic, please help me !!!! :)

Replies are listed 'Best First'.
Re: Sockets and Fork, Please Help Me!!
by mortis (Pilgrim) on Dec 12, 2001 at 22:28 UTC
    Try taking a look at IO::Select, and modifying your design to do non-blocking io with the various file handles. Something like:
    use strict; use warnings; use IO::Handle; use IO::Select; my $s = IO::Select->new(); ... $s->add(0); # STDIN $s->add($telnet->fileno()); $s->add($telnet2->fileno()); while(1) { my @ready = $s->can_read(); last unless @ready; foreach my $fd (@ready) { &handleTelnet1() if $telnet->fileno() == $fd; &handleTelnet2() if $telnet2->fileno() == $fd; &handleStdin() if 0 == $fd; } } ...
    The above code does assume that your $telnet handles are IO::Handle objects.

    Updated: robin pointed out some bugs in the example code relating to stdin. Thanks.

      IO::Select is definitely the right thing to use here, but I think your code can be simplified a little. Firstly, there's no need to use $s->add($telnet->fileno()), because add can take a filehandle as its argument. So $s->add($telnet); will suffice. You have a bug related to that: the can_read method will return the same objects that you added to the IO::Select object, and so in your code when standard input is ready for reading it will return the glob reference for STDIN, rather than the file number. That will never test equal to zero. (Its numeric value will actually be the memory address of the glob.)

      Secondly, if you know all your handles in advance you can just pass them to the IO::Select constructor rather than adding them one by one. And the can_read call can be incorporated directly into the loop condition. So maybe something like:

      use strict; use IO::Select; my $s = IO::Select->new(\*STDIN, $telnet, $telnet2); while (my @ready = $s->can_read()) { for my $ready (@ready) { if ($ready == \*STDIN) { handle_stdin(); } else { handle_telnet($ready); } } }
Re: Sockets and Fork, Please Help Me!!
by Rex(Wrecks) (Curate) on Dec 12, 2001 at 23:01 UTC
    I have used Net::Telnet and STDIN with fork successfully, I used IPC::Shareable to create shared memory which the main loop can monitor. You just have to be really careful about locking the shared memory when any of the procs accesses it.

    Update: It seems this response was not liked by some, so I thought I would clarify.

    The above responses were excellent, the problem is if you want your telnet sockets and STDIN to go about thier business and report results back to you which you can reap at any time, AND self terminate reporting that as well, the above approach can run into overhead.

    If all you need is to monitor output from the telnet sessions there is really no need for those to slow down the response time in your IO::Select loop, all you need to do is fork a couple watchers that do what they need and report stats when they hit things of interest, and at that point you can do what ever you need to to handle the situation, including interupting the STDIN loop.

    Just another way to do it. I like shared memory, but you can use pipes, Unix sockets or whatever method you want to communicate between the processes.

    "Nothing is sure but death and taxes" I say combine the two and its death to all taxes!