Liebe PERL-Gemeinde!Ich habe ein Problem, das bereits an anderen Stellen im Internet diskutiert wurde, doch obwohl ich stundenlang Forumsbeiträge, Tutorials und Dokumentationen gelesen habe und etliches an Ratschlägen ausprobiert habe, konnte ich die Lösung bislang nicht finden.
Die Grundsituation ist folgende: In einem CGI-Script frage ich Daten ab, die dann einen Prozess anstoßen, der länger dauert. Ich möchte nun den Nutzer nicht minutenlang mit der Frage allein lassen, ob denn das Script abgestürzt ist oder immer noch läuft. Wenn also die Anfrage abgeschickt wird, macht mein Programm einen "fork"; im "child"-Prozess wird eine Warteseite erzeugt, die sich in regelmäßigen Abständen auffrischt und dem Nutzer die abgelaufene Zeit anzeigt. Im "parent"-Prozess läuft die Datenverarbeitung ab (oder auch umgekehrt, habe ich auch schon ausprobiert, ändert nichts am Grundproblem). Sobald der "parent" fertig ist, erzeugt er eine TML-Datei, und das ist das Signal für den "child"-Prozess, diese aufzurufen, die dann auch gleichzeitig die Ergebnisse enthält. Sowohl die Daten-Eingabe, als auch die "Waiting"-Seiten
werden von meinem Programm erzeugt; kein externes Programm und kein externes HTML-Dokument wird benötigt.
Im Prinzip läuft auch alles recht gut. Es gibt nur ein Problem - und das ist jenes, welches ich gelöst haben möchte: Normalerweise sollte der "child" die Warteseite erzeugen, dann "sterben", und die Warteseite ruft nach einer Wartezeit das Programm erneut auf, nun aber wiederholt in einer Schleife, um wieder und wieder die Warteseite zu erzeugen - solange, bis das Abbruchsignal kommt.So läuft das Script aber leider nicht! Der "child"-Prozess erzeugt die Warteseite und HÄNGT dann - bis auch der "parent" beendet ist. Erst DANN ruft er nochmals die Warteseite auf, um - wie gewünscht - sofort auf die Ergebnis-Seite hinüberzuspringen.
Das Problem scheint mir offensichtlich darin zu liegen, daß "parent" und "child" nicht vollkommen unabhängig voneinander sind, obwohl ich alles versucht habe, um das zu erreichen. Dadurch scheint der Webserver immer noch auf Dateneingabe des "child"s zu warten - bis eben auch der "parent" beendet ist. Einbau von "exit"s - hat nicht genügt. Schließen von STDIN, STDOUT, STDERR - reicht auch nicht. Aber wo, in aller Welt, sind die Prozesse noch miteinander verknüpft, und wie kann ich diese Verbindung lösen? Wer kann mir weiterhelfen???
Um es deutlich zu machen: natürlich gibt es immer auch Wege, die Strategie zu wechseln, einen "workaround" zu entwickeln. Und sicherlich ist mein Programm noch weit davon entfernt, einen optimalen Code zu enthalten. Aber es geht mir nicht mehr (nur) darum, das Programm IRGENDWIE zum Laufen zu bringen; ich will verstehen, warum dieser "fork" nicht so läuft wie (ich dachte begriffen zu haben daß) er sollte. Wenn ich HIER Probleme mit dem "fork" bekomme, dann kann das übermorgen wieder passieren. Also möchte ich das Problem ein für alle Mal verstehen.
Wer hat das Wissen mir zu helfen???
Unten habe ich ein Demo-Programm abgelegt. Es sollte komplett funktionsfähig sein, mal abgesehen von dem Problem, das ich gelöst haben möchte. Lediglich die "$TmpAbs"-Variable muß noch angepaßt werden. Was ich Euch hier poste ist nicht nur ein Code-Schnipsel Ich hoffe, daß ich Eure Geduld nicht zu sehr strapaziere...
Wielen Dank für Eure Hilfe und Unterstützung,
Euer
chanklaus
P.S. Normalerweise kommentiere ich (fast) jede Programmzeile. Die Kommentare habe ich hier entfernt. Wer den kommentierten Code sehen möchte, dem schicke ich ihn gerne zu.
require 5.004;
use CGI;
use strict;my ($Cgi,$Script,$TmpAbs,$TmpVrt,$HtmOut,$HtmTmp,$Status,$ForkVal,$STime,$Elapsed,$Ticks,$QI);
$Cgi = new CGI;
$Script = $Cgi->script_name();
$TmpAbs = "/www/WEBSERVER/htdocs/tmp";
$TmpVrt = "/tmp";
$HtmOut = sprintf("%s/demo.html",$TmpAbs);
$HtmTmp = sprintf("%s/demo.html.tmp",$TmpAbs);
$STime = $Cgi->param('Time');
$Ticks = $Cgi->param('Tick');
$Status = $Cgi->param('STAT');
if (!defined($Status)) { $Status = 0; }
if ($Status == 0) { &StartPage; }
elsif ($Status == 1) {
if (!open(HTMFILE,">$HtmTmp")) { &ErrorMsg(1,$HtmTmp); }
$ForkVal = fork();
if (!defined($ForkVal)) { &ErrorMsg(0,""); }
if ($ForkVal == 0) {
$Elapsed = "00:00:00";
&WaitingPage(sprintf("%s?STAT=2&Time=%s",$Script,&CurrTime));
close(STDOUT); close(STDERR); close(STDIN);
exit(0); }
else {
print HTMFILE &ProcessPage;
close(HTMFILE);
system("mv $HtmTmp $HtmOut"); }
}
elsif ($Status == 2) {
$Elapsed = &ElapsedTime;
if (-s $HtmOut) { &WaitingPage(sprintf("%s/demo.html",$TmpVrt),0); }
else { &WaitingPage(sprintf("%s?STAT=2&Time=%s",$Script,$STime),5); }
exit(0);
}
sub ErrorMsg {
my ($Stat,$Mess) = @_;
print $Cgi->header(-type =>'text/html');
print $Cgi->start_html(-title => 'DEMO Error Message');
print "<body>\n<center>\n\n";
print "<span style=\"font-size:22pt; color:Green\">DEMO ERROR MESSAGE</span><br>\n<br>\n";
if ($Stat == 0) { print "!!! System error - could NOT fork process !!!<br>\n"; }
elsif ($Stat == 1) { print "!!! System error - could NOT write \"HTML\" file '$Mess'!!!<br>\n"; }
print "</center>\n</body>\n</html>\n";
exit(0); }
sub StartPage {
print $Cgi->header(-type =>'text/html');
print $Cgi->start_html(-title => 'DEMO START PAGE');
print "<body>\n<center>\n<br>\n";
print "<span style=\"font-size:22pt; color:Green\">DEMO START PAGE</span><br>\n<br>\n";
print "<form action=\"$Script\" method=\"post\">\n";
print "<input type=\"hidden\" name=\"STAT\" value=\"1\">\n";
print "<b>TYPE A "TICK NUMBER":</b><br>\n";
print "<input type=\"text\" name=\"Tick\" size=\"10\"><br><br>\n";
print "<input type=\"submit\" value=\"PROCESS\"> <input type=\"reset\" value=\"RESET FORM\">\n";
print "</form>\n</center>\n</body>\n</html>\n"; }
sub ProcessPage {
my $Html = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n<html>\n";
$Html .= "<head>\n <title>DEMO PROCESS PAGE</title>\n";
$Html .= " <meta HTTP-EQUIV=\"Expires\" CONTENT=\"NOW\">\n</head>\n\n";
$Html .= "<body>\n<center>\n<br>\n";
$Html .= "<span style=\"font-size:22pt; color:Green\">DEMO PROCESS PAGE</span><br>\n<br>\n";
$Html .= "<span style=\"font-size:22pt; color:Violet\">...THAT'S THE TEST...</span><br>\n<br>\n";
$Html .= "...<a href=\"$Script\">go back to the DEMO start page</a>...<br>\n";
$Html .= "</center>\n</body>\n</html>\n";
sleep($Ticks);
$Html; }
sub WaitingPage {
my ($Url,$Tact) = @_;
print $Cgi->header(-type =>'text/html');
print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n<html>\n";
print "<head>\n <title>...DEMO is running...</title>\n";
print " <META HTTP-EQUIV=\"refresh\" content=\"$Tact; url=$Url\">\n</head>\n\n";
print "<body>\n<center>\n<br>\n";
print "<span style=\"font-size:22pt; color:Red\">...DEMO is running...</span><br>\n";
print "<br>\n<span style=\"font-size:22pt\">Don't go BACK!</span><br>\n<br>\n";
print "<span style=\"font-size:20pt; color:Blue\">Elapsed Time: $Elapsed</span><br>\n";
print "</center>\n</body>\n</html>\n"; }
sub CurrTime {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $LocTime = "$mday $mon $year $wday $yday $isdst";
$LocTime = sprintf("%02d:%02d:%02d",$hour,$min,$sec);
$LocTime; }
sub ElapsedTime {
my ($Sec,$Min,$Hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $CTime = "$mday $mon $year $wday $yday $isdst";
$CTime = ((($Hour * 60) + $Min) * 60) + $Sec;
($Hour,$Min,$Sec) = split(/:/,$STime);
my $ITime = ((($Hour * 60) + $Min) * 60) + $Sec;
if ($CTime < $ITime) {
$CTime += 86400; }
my $ETime = $CTime - $ITime;
$Sec = $ETime % 60;
$ETime = ($ETime - $Sec) / 60;
$Min = $ETime % 60;
$Hour = ($ETime - $Min) / 60;
$ETime = sprintf("%02d:%02d:%02d",$Hour,$Min,$Sec);
$ETime; }
Datum: 30.11.2007-10:56
