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

Hi. I want to use socketpair() to talk from the parent to a lot of children. But I can't get it to work correctly. The error is: 'Can't use string ("0") as a symbol ref while "strict refs" in use.' How am I doing that? What did I do incorrectly? Also, is there a better way to talk to a bunch of children (and vice versa)? Here is my code:
#!/usr/bin/perl use strict; use warnings; use Socket; use constant LINE_LEN => 24; my $NUM_CHLDS = 5; # Five children my ($parent, $child) = (); my (@pids,$line) = (); my @chld_fh = (); my @par_fh = (); print "Forking..."; for(0 .. $NUM_CHLDS) { $pids[$_] = { child_fh => 0, parent_fh => 0, pid => 0 }; socketpair($pids[$_]->{child_fh},$pids[$_]->{parent_fh}, AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair at $_: $!\n"; unless(($pids[$_]->{pid} = fork())) { # Child die "cannot fork at $_: $!" unless defined $pids[$_]->{pid}; close $pids[$_]->{child_fh}; print "$$: Getting line\n"; sysread($pids[$_]->{parent_fh},$line,LINE_LEN); $line = "$$: " . reverse $line . int(rand(10)); print "$$: Sending line back\n"; syswrite($pids[$_]->{parent_fh},$line,LINE_LEN); close $child; syswrite($pids[$_]->{parent_fh},$line,LINE_LEN); close $child; exit; } print "1.."; } print "\n"; # Parent # chomp($line = <STDIN>); print "$$: Got string, writing\n"; for(0 .. $NUM_CHLDS) { close $pids[$_]->{parent_fh}; syswrite($pids[$_]->{child_fh},$line,LINE_LEN); } print "$$: Wrote, waiting\n"; sleep 1; # For fun for(0 .. $NUM_CHLDS) { sysread($pids[$_]->{child_fh},$line,LINE_LEN); print "Parent pid $$ just read: '$line'\n"; close $pids[$_]->{child_fh}; } wait;

Replies are listed 'Best First'.
Re: Socketpair and a lot of children
by japhy (Canon) on Feb 25, 2006 at 03:53 UTC
    You should have told us what line the error occurred on. I'm guessing
    $pids[$_] = { child_fh => 0, parent_fh => 0, pid => 0 };
    should be
    $pids[$_] = { child_fh => undef, parent_fh => undef, pid => undef };

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
      That was it. Thanks.
Re: Socketpair and a lot of children
by NetWallah (Canon) on Feb 25, 2006 at 07:07 UTC
    Also, your NUM_CHLDS is either a misnomer, or your usage creates one more child than you intended.

    You could make your loop more perl-ish by re-writing it as:

    for(1 .. $NUM_CHLDS) { push @pids, my $pair = { child_fh => undef, parent_fh => undef, pid => undef }; socketpair($pair->{child_fh},$pair->{parent_fh}, AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair at $_: $!\n"; ..... #For Reading the @pids array, instead of for(0 .. $NUM_CHLDS) , use: foreach my $pair(@pids) { close $pair->{parent_fh}; syswrite($pair->{child_fh},$line,LINE_LEN); }

         "For every complex problem, there is a simple answer ... and it is wrong." --H.L. Mencken

Re: Socketpair and a lot of children
by ayrnieu (Beadle) on Feb 25, 2006 at 13:14 UTC
    #! /usr/bin/env perl package Foo::Child; use strict; use warnings; use FileHandle; sub new { my ($class, $pfh, $cfh, $f, @args) = @_; bless {pfh => $pfh, cfh => $cfh, f => $f, args => [$pfh, @args]}, $class; } sub run_and_die { my ($fc) = @_; close $fc->{cfh}; $fc->{f}->($fc, @{$fc->{args}}); close $fc->{pfh}; exit; } sub cfh { $_[0]->{cfh} } sub pfh { $_[0]->{pfh} } package Foo; use strict; use warnings; use Socket; use FileHandle; sub new { bless {children => []}, shift } sub add_child { my ($foo, $f, @args) = @_; my ($cfh, $pfh) = (FileHandle->new, FileHandle->new); $_->autoflush(1) for ($cfh, $pfh); socketpair $cfh, $pfh, AF_UNIX, SOCK_STREAM, PF_UNSPEC or die "socketpair: $!"; push @{$foo->{children}}, Foo::Child->new($pfh, $cfh, $f, @args); $foo } sub run { my ($foo) = @_; for my $c (@{$foo->{children}}) { for (fork) { die "fork failed: $!" unless defined; $c->run_and_die unless $_; close $c->pfh; } } $foo } sub to_all { my ($foo, $s) = @_; print { $_->cfh } $s for @{$foo->{children}}; $foo } sub from_all { my ($foo, @r) = (shift); for (@{$foo->{children}}) { chomp(my $s = readline($_->cfh)); push @r, $s } @r } package main; sub echo_reverse { my ($self, $pfh, $times) = @_; while ($times--) { chomp(my $line = readline($pfh)); print $pfh reverse($line) . "\n"; } } my $echos = new Foo; $echos->add_child(\&echo_reverse, 1) for (1..10); $echos->run; $echos->to_all("hello world!\n"); print "Read this from a child: $_\n" for $echos->from_all;

    If you want to have a really good time, set the number of children to 1 or 2 and then run this program through the perl debugger. In X, at least, I thought this very cool.

    Also, a koders search for socketpair in Perl code.