Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Forking Clients

by gepapa (Acolyte)
on Oct 15, 2008 at 15:30 UTC ( [id://717246]=perlquestion: print w/replies, xml ) Need Help??

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

So I have what I believe is a different question than the norm.

I have a server which has a distinct listener running on multiple ports. What I want to do is be able to make calls to these distinct listeners whenever I want, including simultaneously. So I don't want to necessarily wait on each pid, because I want to be able to do other stuff including making connections to other open listeners. Each call will make the server do something, and I need to get the output back from whatever it is doing.

Here is some sample code I put together to give you a basic idea of what I need to do:

use strict; use Carp; use ClarRPC; #In house module my ($pid1, @resp1) = rpc(10.15.51.208, '1300', 'ping -n 15 10.15.51.20 +8'); my ($pid2, @resp2) = rpc(10.15.51.208, '1301', 'ping -n 15 10.15.51.20 +8'); my ($pid3, @resp3) = rpc(10.15.51.208, '1302', 'ping -n 15 10.15.51.20 +8'); print ("RESP1: @resp1\n"); print ("RESP2: @resp2\n"); print ("RESP3: @resp3\n"); sub rpc { my ($ip, $port, $command) = @_; my @resp; my $pid; my @pids; if ($pid = fork()) { push(@pids, $pid); #waitpid($pid, 0); } elsif (defined $pid) { my $connection = ClarRPC->connect($ip, $port); ($pid, @resp) = $connection->rpc('ClarRPCService::system_call' +, $command); $connection->disconnect(); exit; } return $pid, @resp; }

What I need is the information from @resp. I don't care if it is out of order, and I know the print statements I have won't work. I know I need to wait for a particular pid to complete before having data, but what I need is to be able to wait for that pid without blocking the possibility of the other pid's completing before it. So essentially I need the ability to just get the info from whatever call is complete, at any time.

Any help would be greatly appreciated Thanks

Replies are listed 'Best First'.
Re: Forking Clients
by BrowserUk (Patriarch) on Oct 15, 2008 at 16:19 UTC

    If you don't have an irrational fear of threads, something like this complicated beast would do it :):

    #! perl -slw use strict; use threads; use threads::shared; use Thread::Queue; use ClarRPC; #In house module my $Q = new Thread::Queue; my $ip = '10.15.51.208'; my $command = 'ping -n 15 10.15.51.208'; my @ports = 1300 .. 1302; for my $port ( @ports ) { async{ my $connection = ClarRPC->connect( $ip, $port ); my @results :shared = $connection->rpc( 'ClarRPCService::system_call', $command ); $connection->disconnect(); unshift @results, $port; $Q->enqueue( \@results, undef ); }->detach; } for ( 1 .. @ports ) { while( my $ref = $Q->dequeue ) { my( $port, @results ) = @$ref; print "$port : @results"; } } __END__ c:\test>junk4 1300 : 1 2 3 4 5 6 7 8 9 10 1301 : 1 2 3 4 5 6 7 8 9 10 1302 : 1 2 3 4 5 6 7 8 9 10

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Hi first, thanks for your reply, but I have a few questions.

      use strict; use threads; use Thread::Queue; use ClarRPC; my $queue = new Thread::Queue; rpc('10.15.51.208', '1300', 'ping -n 50 10.15.51.208'); rpc('10.15.51.208', '1301', 'ping -n 10 10.15.51.208'); rpc('10.15.51.208', '1302', 'ping -n 50 10.15.51.208'); while (my $ref = $queue->dequeue) { my ($port, @results) = @$ref; print "$port : @results\n"; } sub rpc { my ($ip, $port, $command) = @_; async{ my $connection = ClarRPC->connect($ip, $port); my @resp :shared = $connection->rpc('ClarRPCService::system_ca +ll', $command); $connection->disconnect(); unshift(@resp, $port); $queue->enqueue(\@resp, undef); }->detach }

      So in this case note the 1301 port command is a -n 10, so this one will return prior to the others. So what I see in this instance is that the program exits, as soon as the 1301 port returns its info. What I was hoping for was for something that wouldn't exit until they were all done. I don't see anything glaring that I missed in my version which would make it different than yours in functionality.

      Any ideas? Thanks

        You need to wrap the while loop in a for loop that iterates once for each client you start:

        use strict; use threads; use threads::shared; ### I omitted this from my example above initiall +y. use Thread::Queue; use ClarRPC; my $queue = new Thread::Queue; rpc('10.15.51.208', '1300', 'ping -n 50 10.15.51.208'); rpc('10.15.51.208', '1301', 'ping -n 10 10.15.51.208'); rpc('10.15.51.208', '1302', 'ping -n 50 10.15.51.208'); for( 1 .. 3 ) { ## Must iterate once for each thread started ### while (my $ref = $queue->dequeue) { my ($port, @results) = @$ref; print "$port : @results\n"; } } sub rpc { my ($ip, $port, $command) = @_; async{ my $connection = ClarRPC->connect($ip, $port); my @resp :shared = $connection->rpc( 'ClarRPCService::system_call', $command ); $connection->disconnect(); unshift(@resp, $port); $queue->enqueue(\@resp, undef); }->detach }

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Forking Clients
by Fletch (Bishop) on Oct 15, 2008 at 15:43 UTC

    Using a framework such as POE and letting it take care of the nasty details makes this kind of thing much, much easier . . .

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      POE is a pretty awesome bit of work, a bit of a learning curve but worth it if you do stuff like that regularly.

                      - Ant
                      - Some of my best work - (1 2 3)

      POE seems interesting, I will investigate it, but in the current situation it is probably not going to work since I need to avoid adding non-core Perl modules at all costs.
Re: Forking Clients
by mr_mischief (Monsignor) on Oct 15, 2008 at 15:38 UTC
    Does the information about non-blocking waits in waitpid help you any? If your platform supports it, that sounds like just what you need.
Re: Forking Clients
by JavaFan (Canon) on Oct 15, 2008 at 16:11 UTC
    Well, if that's your program, you could just print @resp from the children.

    If the point is that the parent needs all the data from @resp, you could instead of doing a fork, do a pipe open (using '|-' or '-|' -- I always forget which one is which). Have the child processes write @resp to the pipe; the parent can use a select loop (or use IO::Select) and read from the pipe. Or you could use shared memory to pass the information back. Alternatively, you don't use subprocesses, but threads and share some variables.

Re: Forking Clients
by AnomalousMonk (Archbishop) on Oct 15, 2008 at 23:09 UTC
    Is gepapa aware that the OPed code has the following line:
    $pid, @resp = $connection->rpc('ClarRPCService::system_call', $command +);
    If this highly suspicious statement is just, as I assume, a cut/paste typo, can gepapa please update the OP?

    If this is a valid statement, can someone please explain to a forking tyro such as myself just what is going on here?

      The lexical variable $pid is evaluated and the result is then discarded. The variable is not tie-d to anything, so there can be no side effect. Don't you see a warning from this (although you don't use warnings; in your sample code)? All output from the $connection->rpc() function call is assigned to @resp. What's the point of having $pid in the statement? A typo or a thinko is strongly suggested.
      >perl -wMstrict -le "my $pid = 'foo'; my @resp = qw{ a b c }; sub S { return qw{ FOO bar quux } } $pid, @resp = S(); print qq{$pid @resp}; " Useless use of private variable in void context at -e line 1. foo FOO bar quux
        I added the $pid part last second, it should have parens around the two variables I will fix it. I didn't really pay attention to it, I fixed the OP Thanks.
      Hi, What is your main worry with the statement? I guess I am not seeing it.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://717246]
Approved by mr_mischief
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (7)
As of 2024-04-19 12:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found