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

use IO::Socket::INET; my $socket = IO::Socket::INET->new( PeerAddr => 'localhost', PeerPort => '9000', Proto => 'tcp', Type => SOCK_STREAM ) or die "Error: cant create listening socket: $!\n"; $socket->autoflush(1); # so output gets there right away die "can't fork: $!" unless defined( $kidpid = fork() ); #parent process if ($kidpid) { while ( defined( my $line = <$socket> ) ) { print STDOUT $line; } kill( "TERM", $kidpid ); # send SIGTERM to child } #the child process else { my $line = <STDIN>; while ( defined($line) ) { print $socket $line; } } close($socket);
Above is the client code that writes/reads from a socket. Usage: ./client, and then input through STDIN to write to the socket. Is there a way I can pass $ARGV[0] in the child process like: print $socket $ARGV[0] ?

Replies are listed 'Best First'.
Re: pass ARGV to STDIN
by alexm (Chaplain) on Mar 07, 2008 at 20:01 UTC

    From IO::Socket::INET docs:

    If "Listen" is defined then a listen socket is created, else if the socket type, which is derived from the protocol, is SOCK_STREAM then connect() is called.

    You're using a connect() socket only, so your process family won't talk much. You need at least one process listening and the other connecting so they can speak; but please note that it will be a client/server (i.e. child/parent) dialog, so the parent won't be able to say a thing until the child requests. If you need a different kind of dialog, then you should change your path to the IPC route.

    Update: This is the classic ping-pong example, that you could find helpful...

    #!/usr/bin/perl use IO::Socket::INET; use strict; use warnings; if (my $pid = fork()) { my $listen = IO::Socket::INET->new( LocalAddr => 'localhost', LocalPort => 9000, Proto => 'tcp', Listen => 1, ) or die "Cannot create listening socket: $!\n"; my $client = $listen->accept() or die "Cannot get a connection: $!\n"; $client->autoflush(1); while (defined(my $line = <$client>)) { print "server < $line"; sleep 1; pong($client); } } else { print "waiting for parent to setup...\n"; sleep 1; my $sock = IO::Socket::INET->new( PeerAddr => 'localhost', PeerPort => 9000, Proto => 'tcp', Type => SOCK_STREAM ) or die "Cannot create connecting socket: $!\n"; $sock->autoflush(1); ping($sock); while (defined(my $line = <$sock>)) { print "client < $line"; sleep 1; ping($sock); } } sub ping { my ($fh) = @_; print "client > ping\n"; print {$fh} "ping\n"; } sub pong { my ($fh) = @_; print "server > pong\n"; print {$fh} "pong\n"; }
      Thanks. This is the scenario: I have a server and a client. The client part of the code is what i posted. The client forks with the parent listening , and child sending requests to the server and not the parent. Now the question is reduced to: how do i pass the ARGV[0] (environment) to the child's STDIN . I get that some IPC mechanism to be used. I tried with pipes, no luck. In effect the client should be called with some command-line arg (./client arg) , and not input through STDIN interactively. Any suggestions please.

        Why make things more complicated than they are? If the idea is to send commandline arguments to the server, then just send them (as you would in the parent) and don't read from STDIN — or maybe read from STDIN only if nothing is specified on the commandline, e.g. like this:

        ... #the child process else { unless (@ARGV) { # read a line from stdin, if no args given on command line my $line = <STDIN>; chomp $line; push @ARGV, split(' ', $line); } print $socket "$_\n" for @ARGV; } ...
        The client forks with the parent listening , and child sending requests to the server and not the parent.

        Your parent is actually reading from the server, not listening.

Re: pass ARGV to STDIN
by Joost (Canon) on Mar 07, 2008 at 18:48 UTC
Re: pass ARGV to STDIN
by almut (Canon) on Mar 07, 2008 at 18:55 UTC

    Maybe I'm misunderstanding what you want to do, but the situation is that the child will already have a copy of @ARGV (as it was at the time of the fork), so there's not really a need to pass it... This is a one-time thing, though. In case you'd need to pass further info after the fork, you'd have to use regular IPC mechanisms, as the child is a separate process then.