Hi everybody, I am currently working on a project and I need parent process to fork multiple children to do the actual work, but maintain a bidirectional communication with each of the children to send them commands and receive back, agregate and display summary results.
According to the perlipc tutorial and other resources, the best in this case is to use either pair of unidirectional pipes, or use anonymous sockets created by socketpair function. I chose socketpair, but I discovered very weird behaviour and could not find any workaround so far. Consider the following code: #!/usr/bin/perl -w use strict; use warnings; use Socket; use IO::Handle; use POSIX 'WNOHANG'; my $kids = 0; # Number of kids alive my %kids = (); # kid PID => Socket my ($child, $parent); foreach my $i (1..3) { socketpair($child, $parent, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!"; #pipe($parent, $child); $child->autoflush(1); $parent->autoflush(1); print "Created child socket: ". fileno($child) . "\n"; print "Created parent socket: ". fileno($parent) . "\n"; die "cannot fork: $!" unless defined(my $pid = fork); unless ($pid) { close $child; do_child($parent); exit(0); } else { close $parent; $kids++; $kids{$pid} = $child; } } $SIG{INT} = \&HUNTER; $SIG{CHLD} = \&REAPER; foreach my $kid (keys %kids) { print "Sending message to the kid $kid\n"; print {$kids{$kid}} "Parent Pid $$ is sending this\n"; } map { close $_ } values(%kids); sleep while($kids); sub do_child { my $parent = shift; print "Child $$\n"; chomp(my $line = <$parent>); print "Child Pid $$ just read this: '".(defined($line)?$line:'undef')."'\n"; close $parent; } sub HUNTER { print "Killing children\n"; my $count = kill INT => keys(%kids); print "Killed $count children\n"; } sub REAPER { while ((my $kid = waitpid(-1,WNOHANG)) > 0) { $kids--; print "Reaped kid $kid\n"; } unless ($kids) { print "Parent exit\n"; exit(0); } } This is the working, but simplified example. For simplicity, in this snippet I am trying just to write from parent process to all children, not in both directions. In the parent process, I create socket pair in loop, fork and store the handle to communicate with the newly created child in the hash. I then try to send message to all stored sockets (to all children). If I run this example, I get the following output: Created child socket: 3 Created parent socket: 4 Child 4230 Created child socket: 3 Created parent socket: 4 Use of uninitialized value $line in chomp at ./test_bidirectional.pl line 52. Child Pid 4230 just read this: 'undef' Created child socket: 3 Created parent socket: 4 Sending message to the kid 4232 Sending message to the kid 4231 Sending message to the kid 4230 Child 4231 Use of uninitialized value $line in chomp at ./test_bidirectional.pl line 52. Child Pid 4231 just read this: 'undef' Child 4232 Child Pid 4232 just read this: 'Parent Pid 4229 is sending this' Reaped kid 4230 Reaped kid 4231 Reaped kid 4232 Parent exit The socketpair() function called in loop returns the same pair of sockets each call. So all children are reading from the same socket! Is this the correct behavior? I would expect, that the socketpair function creates and returns new pair of sockets each call. I need to have different pair of sockets to communicate with each child, otherwise they are competing for the incoming data and only one receves them. In the code is commented pipe() function. If you comment the createsocketpair and uncomment the pipe function, result is the same. Even the pipe function does not create new pair of handles each call. Does anyone know, what am I doing wrong, what am I missing? What is the correct way to establish communication with multiple subprocesses? I really need to get this working somehow. If needed, I will gladly provide more information. Thanks in advance for your time Regards Honza Mach P.S. My system information: Perl: v5.10.1 (*) built for x86_64-linux-gnu-thread-multi WS: Linux Mint 10, Linux 2.6.35-28-generic x86_64 GNU/Linux
smime.p7s
Description: S/MIME cryptographic signature