FrankS: "geforktes" Perlscript bleibt hängen.

Hallo Perlgemeinde!

Ich knoble an einem Problem:

Ich muß zur Steuerung eines Gerätes per TCP ein Kommando (ASCII) senden, die Antwort lesen und ausgeben und die Antwort per Timer überwachen.
Meine Idee dazu siehe unten (nur ein Ausschnitt). Es wird ein Socket geöffnet, per fork ein neuer Prozess gestartet. Der "schnellere" Prozess killt jeweils den anderen und beendet sich dann: Der ElternProzess sendet das Kommando ($command + 0x0d 0x0a 0x00), empfängt die Antwort, killt den Timerprozess und beendet sich, der Timerprozess lauert auf das Ende von sleep und killt den Sender/Empfänger Prozess und beendet sich auch. Das ganze läuft als EXE (das Thema des Threads stimmt also nicht ganz), erstellt mit Perl2Exe V8.00 und ActivState Perl v5.8.2 Build 808 unter WinXP und wird in regelmäßigen Abständen aus einem Batchfile aufgerufen.

Manchmal, eher selten, bleibt nun die exe hängen, braucht 50% Prozessorlast und kann nur noch per Taskmanager abgeschossen werden. Ein Etherealtrace zeigt, daß die Kommunikation zw. PC und Target eigentlich erfolgreich war. Jetzt die Frage: Liegts an meiner Implementierung, an Perl oder Perl2Exe, an WinXP? Im Taskmanager kann man nicht erkennen, um welchen der beiden Prozesse es sich handelt.

Vielleicht könnt Ihr einen Fehler entdecken? Oder habt eine andere Idee. Dafür schon mal vielen Dank!

Gruß Frank

[...]

init Vars

read Parameter

[...]

Socket öffnen

$socket = new IO::Socket::INET(
   PeerAddr => $target,
   PeerPort => $PORT,
   Proto    => 'tcp',
) or die "Can't connect target $target!";

eigene ID merken

$ParentId = $$;

Prozess für Timer erzeugen

$TimerPid = fork();
die "fork: $!" unless defined $TimerPid;

if ($TimerPid) {
    # command an target senden
    print $socket "$command \x0d\x0a\0x00";
    # antwort lesen und ausgeben, Endekennzeichen ist 0x0a
    while ($char ne "\x0a") {
       $char=$socket->getc();
       print $char;
    }
    $socket->close();
    # Timer Prozess killen
    kill("KILL",$TimerPid);
}else{
    sleep ($timeout);
    print "Timeout! No answer from target $target!\n";
    $socket->close();
    # Elternprozess killen
    kill("KILL",$ParentId);
}
exit;

  1. Hallo,

    ...Der "schnellere" Prozess killt jeweils den anderen und beendet sich dann: Der ElternProzess sendet das Kommando ($command + 0x0d 0x0a 0x00), empfängt die Antwort, killt den Timerprozess und beendet sich, der Timerprozess lauert auf das Ende von sleep und killt den Sender/Empfänger Prozess und beendet sich auch.

    [...]

    # Elternprozess killen
        kill("KILL",$ParentId);
    }
    exit;

    fork: ...The function returns the child pid to the parent process and 0 to the child process on success. If it fails, it returns the undefined value to the parent process and no child process is created. If you fork your child process, you'll hava to wait on their zombies when they die. See the wait function for more information....

    Da Dein Problem sich stark nach einer racing condition anhört, würde ich das Beenden des parent-prozesses ihm sich selbst überlassen:

    Elternprozess nicht killen

    }
    exit;

    Hier sind wir wieder im parent-prozess

    Hier passende wait-funktion einfügen

    exit;

    Der parent-prozess hat sich beendet

    Ein zweiter möglicher Fehler:

    $TimerPid = fork();

    hier bist Du schon im child-prozess und $TimerPid ist die pid des childs, oder im Fehlerfall gleich 0, aber eben nicht undefined!

    die "fork: $!" unless defined $TimerPid;

    Dies macht daher wenig Sinn, denn $TimerPid ist eben immer defined.

    Es ist länger her, daß ich in Perl geproggt habe, drum verzeihe mir wenn ich was übersehen habe, vielleicht konnte ich ja trotzdem helfen.

    cu, ziegenmelker