This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Better advertising.
[perl5.git] / pod / perlipc.pod
index 6467a29..e591f54 100644 (file)
@@ -121,11 +121,15 @@ signal handlers like this:
     $SIG{CHLD} = \&REAPER;
     # now do something that forks...
 
-or even the more elaborate:
+or better still:
 
     use POSIX ":sys_wait_h";
     sub REAPER {
        my $child;
+       # If a second child dies while in the signal handler caused by the
+       # first death, we won't get another signal. So must loop here else
+       # we will leave the unreaped child as a zombie. And the next time
+       # two children die we get another zombie. And so on.
         while (($child = waitpid(-1,WNOHANG)) > 0) {
            $Kid_Status{$child} = $?;
        }
@@ -660,14 +664,14 @@ instead.
     BEGIN { $ENV{PATH} = '/usr/ucb:/bin' }
     use Socket;
     use Carp;
-    $EOL = "\015\012";
+    my $EOL = "\015\012";
 
     sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
 
     my $port = shift || 2345;
     my $proto = getprotobyname('tcp');
 
-    ($port) = $port =~ /^(\d+)$/                        || die "invalid port";
+    ($port) = $port =~ /^(\d+)$/                        or die "invalid port";
 
     socket(Server, PF_INET, SOCK_STREAM, $proto)       || die "socket: $!";
     setsockopt(Server, SOL_SOCKET, SO_REUSEADDR,
@@ -703,7 +707,7 @@ go back to service a new client.
     BEGIN { $ENV{PATH} = '/usr/ucb:/bin' }
     use Socket;
     use Carp;
-    $EOL = "\015\012";
+    my $EOL = "\015\012";
 
     sub spawn;  # forward declaration
     sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
@@ -711,7 +715,7 @@ go back to service a new client.
     my $port = shift || 2345;
     my $proto = getprotobyname('tcp');
 
-    ($port) = $port =~ /^(\d+)$/                        || die "invalid port";
+    ($port) = $port =~ /^(\d+)$/                        or die "invalid port";
 
     socket(Server, PF_INET, SOCK_STREAM, $proto)       || die "socket: $!";
     setsockopt(Server, SOL_SOCKET, SO_REUSEADDR,
@@ -724,10 +728,13 @@ go back to service a new client.
     my $waitedpid = 0;
     my $paddr;
 
+    use POSIX ":sys_wait_h";
     sub REAPER {
-       $waitedpid = wait;
+       my $child;
+        while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
+           logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
+       }
        $SIG{CHLD} = \&REAPER;  # loathe sysV
-       logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
     }
 
     $SIG{CHLD} = \&REAPER;
@@ -745,6 +752,7 @@ go back to service a new client.
                at port $port";
 
        spawn sub {
+           $|=1;
            print "Hello there, $name, it's now ", scalar localtime, $EOL;
            exec '/usr/games/fortune'           # XXX: `wrong' line terminators
                or confess "can't exec fortune: $!";
@@ -864,6 +872,7 @@ to be on the localhost, and thus everything works right.
     use Carp;
 
     BEGIN { $ENV{PATH} = '/usr/ucb:/bin' }
+    sub spawn;  # forward declaration
     sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
 
     my $NAME = '/tmp/catsock';
@@ -879,10 +888,13 @@ to be on the localhost, and thus everything works right.
 
     my $waitedpid;
 
+    use POSIX ":sys_wait_h";
     sub REAPER {
-       $waitedpid = wait;
+       my $child;
+        while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
+           logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
+       }
        $SIG{CHLD} = \&REAPER;  # loathe sysV
-       logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
     }
 
     $SIG{CHLD} = \&REAPER;
@@ -900,6 +912,29 @@ to be on the localhost, and thus everything works right.
        };
     }
 
+    sub spawn {
+       my $coderef = shift;
+
+       unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
+           confess "usage: spawn CODEREF";
+       }
+
+       my $pid;
+       if (!defined($pid = fork)) {
+           logmsg "cannot fork: $!";
+           return;
+       } elsif ($pid) {
+           logmsg "begat $pid";
+           return; # I'm the parent
+       }
+       # else I'm the child -- go spawn
+
+       open(STDIN,  "<&Client")   || die "can't dup client to stdin";
+       open(STDOUT, ">&Client")   || die "can't dup client to stdout";
+       ## open(STDERR, ">&STDOUT") || die "can't dup stdout to stderr";
+       exit &$coderef();
+    }
+
 As you see, it's remarkably similar to the Internet domain TCP server, so
 much so, in fact, that we've omitted several duplicate functions--spawn(),
 logmsg(), ctime(), and REAPER()--which are exactly the same as in the
@@ -951,7 +986,7 @@ looks like this:
 
 Here are what those parameters to the C<new> constructor mean:
 
-=over
+=over 4
 
 =item C<Proto>
 
@@ -1146,7 +1181,7 @@ does nothing but listen on a particular port for incoming connections.
 It does this by calling the C<< IO::Socket::INET->new() >> method with
 slightly different arguments than the client did.
 
-=over
+=over 4
 
 =item Proto
 
@@ -1183,8 +1218,8 @@ clear out.
 
 Once the generic server socket has been created using the parameters
 listed above, the server then waits for a new client to connect
-to it.  The server blocks in the C<accept> method, which eventually an
-bidirectional connection to the remote client.  (Make sure to autoflush
+to it.  The server blocks in the C<accept> method, which eventually accepts a
+bidirectional connection from the remote client.  (Make sure to autoflush
 this handle to circumvent buffering.)
 
 To add to user-friendliness, our server prompts the user for commands.
@@ -1246,6 +1281,11 @@ find yourself overly concerned about reliability and start building checks
 into your message system, then you probably should use just TCP to start
 with.
 
+Note that UDP datagrams are I<not> a bytestream and should not be treated
+as such. This makes using I/O mechanisms with internal buffering
+like stdio (i.e. print() and friends) especially cumbersome. Use syswrite(),
+or better send(), like in the example below.
+
 Here's a UDP program similar to the sample Internet TCP client given
 earlier.  However, instead of checking one host at a time, the UDP version
 will check many of them asynchronously by simulating a multicast and then
@@ -1296,6 +1336,11 @@ with TCP, you'd have to use a different socket handle for each host.
        $count--;
     }
 
+Note that this example does not include any retries and may consequently
+fail to contact a reachable host. The most prominent reason for this
+is congestion of the queues on the sending host if the number of
+list of hosts to contact is sufficiently large.
+
 =head1 SysV IPC
 
 While System V IPC isn't so widely used as sockets, it still has some