Christian: Multithreaded Server - $SIG{CHLD} = sub { wait } beendet Server

Beitrag lesen

Hallo zusammen,

ich versuche gerade die Prinzipien eines multithreaded Servers zu verstehen und habe dafür natürlich ein kleines Beispiel:

  
#!/usr/bin/perl -w  
  
use strict;  
use IO::Socket;  
  
# Port waehlen  
use constant MYPORT => 1234;  
  
my $client = '';  
  
my $sock = new IO::Socket::INET(LocalPort => MYPORT,  
                       Reuse     => 1,  
                       Listen    => 5)  
      or die "can't create local socket: $@\n";  
  
$SIG{'CHLD'} = 'IGNORE';  
#$SIG{'CHLD'} = sub { my $c = wait(); print "Child $c terminated.\n" };    # Zombies verhindern  
  
print "Accepting connections on Port ", MYPORT, "...\n";  
while ($client = $sock->accept()) {  
  # Verbindung ist aufgebaut  
  print "Accepted connection from ",  
          $client->peerhost(), ":", $client->peerport(), "\n";  
  
  # Erzeugen eines Kindprozesses und Uebergabe an $client.  
  if (fork() == 0) { # Kindprozess  
  
    $sock->close; # brauch ich hier nicht mehr  
  
    # Eingabe wird untersucht und in Großbuchstaben ausgegeben  
    do {  
      my $input = <$client>;  
      chomp($input);  
      print uc($input)."\n";  
    } while(length($input) > 1);  
  
    exit(0);  
  } # End fork()  
  
  $client ->close; # nicht benötigt    <---------- (**)  
}  

Es wird ein Prozess gestartet, der auf Port 1234 lauscht. Die while-Schleife wartet auf eingehende Verbindungen. Falls eine kommt, wird ge-forkt und gleich weiter gelauscht. Der Kindprozess übernimmt die Kommunikation und gibt einfach jede Zeile, die er bekommt in Großbuchstaben zurück.

Funktioniert soweit wunderbar, aber nur mit

  
$SIG{CHLD} = 'IGNORE';  

Lasse ich den SIGCHLD-Handler ganz weg, bekomme ich natürlich Zombies. Was aber, wenn ich die PID des Kind verwenden möchte? Mit

  
$SIG{'CHLD'} = sub { my $c = wait(); print "Child $c terminated.\n" };  

wird der Serverprozess beendet, sobald das erste Kind stirbt, was natürlich sinnlos ist. Die Meldung "Child ... terminated" erscheint noch, danach wird die while-Schleife des Servers verlassen und dieser terminiert.

Außerdem verstehe ich nicht, wieso ich z.B. im Serverprozess die Client-Verbindung beenden kann (s. (**)), diese aber im Kindprozess dann noch zur Verfügung steht. Die Variablen werden ja kopiert, aber der Socket ist doch trotzdem nur einmal da. Das sieht irgendwie aus, als würden beide Prozesse am selben Objekt operieren, ohne zu wissen, was der andere tut. Das kann doch nicht gut gehen.

Würde mich freuen, wenn ihr mich ein bisschen aufklären könntet! ;-) Insbesondere wie man an die Child-PID kommt, ohne dass der Server dabei draufgeht.

Viele Grüße
Christian