Killt ein Klick auf Stopp-Button ein CGI-Script?
FrankS
- webserver
0 CaptainSolo0 FrankS0 Christian Kruse0 Harry0 Christian Kruse0 Harry
Hallo allezusammen!
Eine Frage beschäftigt mich zurzeit:
Wird ein CGI-Script vom Server gekillt, wenn während der Laufzeit des Scripts der User auf den Stopp-Button im Browser drückt?
Danke für Eure Antworten,
Gruß Frank
Hi!
Natürlich wird es nicht gestoppt, da das Script wie Du schon selbst richtig gesagt hast auf dem Server abläuft nicht auf dem User-Rechner.
Das heisst, der User kann nur die Ansicht / Anwendung auf seinem Rechner beenden durch den Stopp-Button, nicht aber auf dem Server.
Gruss,
CS
Hi!
Auch Hi!
Natürlich wird es nicht gestoppt, da das Script wie Du schon selbst richtig gesagt hast auf dem Server abläuft nicht auf dem User-Rechner.
Ich bin mir nur nicht sicher, ob der Browser dem Server nicht "Bescheid sagt" - nach dem Motto: vergiß den Request, und tschüs. Schließlich liefert das Script am Ende eine Ausgabe, die zum Browser geschickt werden soll(te). Der Browser erwartet nun aber nichts mehr. D.h., daß sonst übliche Spiel http-request <-> http-response wird unterbrochen. Nur wo?
Gruß Frank
Moin.
Ich bin mir nur nicht sicher, ob der Browser dem Server nicht "Bescheid sagt" - nach dem Motto: vergiß den Request, und tschüs. Schließlich liefert das Script am Ende eine Ausgabe, die zum Browser geschickt werden soll(te). Der Browser erwartet nun aber nichts mehr. D.h., daß sonst übliche Spiel http-request <-> http-response wird unterbrochen. Nur wo?
Wenn du es nicht weißt, dann mach den Pepsi-Test. ;)
Schreibe ein kleines Script, welches alle halbe Sekunde eine Zahl ausgibt, sowohl zum Browser, als auch in eine Logdatei. Zählen von 1 bis 100.
Wenn das Skript nicht abgebrochen wird, müßten alle Zahlen in der Logdatei stehen. Wenn nicht, wird irgendwo mittendrin abgebrochen.
- Sven Rautenberg
Auch Moin!
Wenn das Skript nicht abgebrochen wird, müßten alle Zahlen in der Logdatei stehen. Wenn nicht, wird irgendwo mittendrin abgebrochen.
Damit kann er zwar seine spezielle Konfiguration testen, aber man kann leider keine allgemeinen Rueckschluesse ziehen. Und ein CGI-Script sollte ja schon auch mit verschiedenen Webservern laufen, oder?
So long
Nochmal Moin.
Damit kann er zwar seine spezielle Konfiguration testen, aber man kann leider keine allgemeinen Rueckschluesse ziehen. Und ein CGI-Script sollte ja schon auch mit verschiedenen Webservern laufen, oder?
Was spricht dagegen, die eigene Konfiguration zu testen?
Abgesehen davon, daß ich bezweifle, daß man das durch Konfigurieren hinkriegen könnte: Falls ja, möchte man ja irgendwie wissen, ob die geänderte Konfiguration auch funktioniert, damit man weiß, was man anderswo evtl. ändern muß.
- Sven Rautenberg
Re!
Was spricht dagegen, die eigene Konfiguration zu testen?
Na nichts, sagt ja auch keiner. Man darf dann nur nicht sagen, bei mir funktioniert es so, also *ist das so*.
Abgesehen davon, daß ich bezweifle, daß man das durch Konfigurieren hinkriegen könnte: Falls ja, möchte man ja irgendwie wissen, ob die geänderte Konfiguration auch funktioniert, damit man weiß, was man anderswo evtl. ändern muß.
Konfiguration meinte ich hier in einem etwas globalerem Sinne, also ungefaehr "verwendete Software".
So long
Hoi,
Natürlich wird es nicht gestoppt,
Das ist leider falsch. Dem Script wird erst ein SIGTERM und dann ein
SIGKILL geschickt.
da das Script wie Du schon selbst richtig gesagt hast auf dem
Server abläuft nicht auf dem User-Rechner.
Das hat damit nichts zu tun. Wenn du den Request per Stop-Button oder
per Escape abbrichst, wird die Verbindung zum Server gekillt. Das merkt
der Apache und er reagiert dementsprechend darauf.
Das heisst, der User kann nur die Ansicht / Anwendung auf seinem
Rechner beenden durch den Stopp-Button, nicht aber auf dem Server.
Das tut ja auch nicht der User, sondern der Server.
Gruesse,
CK
Holladiwaldfee.
Natürlich wird es nicht gestoppt,
Das ist leider falsch. Dem Script wird erst ein SIGTERM und dann ein
SIGKILL geschickt.
Sache des Programmierers. In PHP kann man das z.B. mit ignore_user_abort(true) verhindern:http://www.php.net/manual/en/function.ignore-user-abort.php
Ciao,
Harry
Hoi,
Sache des Programmierers.
Nein, ist es nicht. Man kann den SIGTERM abfangen, ja. Aber den SIGKILL
kann man in keinem Fall abfangen.
In PHP kann man das z.B. mit ignore_user_abort(true)
verhindern:http://www.php.net/manual/en/function.ignore-user-abort.php
Diese Funktion kann den SIGTERM abfangen.
Gruesse,
CK
Holladiwaldfee.
Sache des Programmierers.
Nein, ist es nicht. Man kann den SIGTERM abfangen, ja. Aber den SIGKILL
kann man in keinem Fall abfangen.
In PHP kann man das z.B. mit ignore_user_abort(true)
verhindern:http://www.php.net/manual/en/function.ignore-user-abort.php
Diese Funktion kann den SIGTERM abfangen.
Dann erklär mir doch bitte, wozu diese Funktion dann überhaupt gut ist. Wann wird SIGKILL gesendet und vom wem ? Wahrscheinlich vom Apache an sien PHP-Modul oder irgendeinen Kind-Prozess, wenn der auf SIGTERM nicht reagiert.
Aber dann wäre ja der Sinn der Funktion ignore_user_abort völlig für'n Eimer, wenn gleich nach SIGTERM alles mit SIGKILL abgewürgt wird ?!
Rätselnd,
Harry
Hoi,
Dann erklär mir doch bitte, wozu diese Funktion dann überhaupt gut
ist. Wann wird SIGKILL gesendet und vom wem?
Vom Apachen an den Child-Prozess, nach dem dieser eine gewisse Zeit
lang nicht auf SIGTERM reagiert.
Wahrscheinlich vom Apache an sien PHP-Modul oder irgendeinen
Kind-Prozess, wenn der auf SIGTERM nicht reagiert.
Genau.
Aber dann wäre ja der Sinn der Funktion ignore_user_abort völlig
für'n Eimer, wenn gleich nach SIGTERM alles mit SIGKILL abgewürgt
wird ?!
Sozusagen. Sie gewinnt nur Zeit.
Gruesse,
CK
Hollahü !
Aber dann wäre ja der Sinn der Funktion ignore_user_abort völlig
für'n Eimer, wenn gleich nach SIGTERM alles mit SIGKILL abgewürgt
wird ?!
Sozusagen. Sie gewinnt nur Zeit.
So'n scheeeeß ! Na, trotzdem Danke für die Erklärung :-)
Ciao,
Harry
(der sich gerade fragt, warum das net so im PHP-Manual steht) :-|
Hi all!
Rätselnd,
genauso gehts jetzt mir...
Was also muß ich tun, um ein Script (Perl), welches aufwändige Dateioperationen durchführt, vor dem "User zu schützen"? Ein Abbruch zwischendurch wäre schlimm. Ich werde mal versuchen, rauszukiegen, wie ich auf das SIGTERM im Script reagieren kann um damit das SIGKILL zu verhindern.
Aber vielleicht kann mir ja auch hier einer einen Tipp geben?
Auf die Schnelle werde ich heute abend mal einen Versuch auf dem Server machen, so wie es Sven vorgeschlagen hat. Dann kann ich vielleicht wieder ruhiger schlafen - oder auch nicht...
Gruß Frank
Hoi,
Was also muß ich tun, um ein Script (Perl), welches aufwändige
Dateioperationen durchführt, vor dem "User zu schützen"? Ein
Abbruch zwischendurch wäre schlimm. Ich werde mal versuchen,
rauszukiegen, wie ich auf das SIGTERM im Script reagieren kann um
damit das SIGKILL zu verhindern.
Du koenntest das folgende versuchen:
use POSIX qw/setsid/;
....
my $pid = fork;
unless($pid) {
die 'could not fork!' unless defined $pid;
# process is no longer a child
die 'could not remove session' unless setsid;
}
else {
# main process ends
exit 0;
}
Das sollte theoretisch gehen -- aber da ist keine Garantie!
Gruesse,
CK
Hi,
Du koenntest das folgende versuchen:
[...]
ich werde mir das ansehen und versuchen, es zu verstehen - ich habe noch nie 'geforkt'.
Jetzt ist erstmal Schluß für heute - morgen wieder.
Besten Dank jedenfalls an alle für die Antworten
Gruß Frank
Hoi,
ich werde mir das ansehen und versuchen, es zu verstehen - ich habe
noch nie 'geforkt'.
Sorry. Die Erklaerung habe ich vergessen. Also hier nachgereicht:
use POSIX qw/setsid/; # das Modul, das die POSIX-Schnittstelle nachbildet
....
my $pid = fork; # hier wird ein vollkommen gleichwertiger Prozess erzeugt
unless($pid) { # $pid ist 0 im Child-Prozess, undefined wenn fork nicht geklappt hat
die 'could not fork!' unless defined $pid; # tja, wie gesagt
# process is no longer a child
die 'could not remove session' unless setsid; # (1)
}
else {
# main process ends
exit 0; # (2)
}
(1) Tja, hier wird setsid benutzt, um das Kind aus der Prozessgruppe
herauszuloesen.
Prozesse sind unter Unix hierarchisch angeordnet. Das heisst, wenn du
dich einloggst auf deinem UNIX-System und ein 'ls' eingibst, dann
ist das 'ls' in Wahrheit schon ein Child, ein Child deiner Shell. Du
koenntest dir die Prozess-Struktur ungefaehr so vorstellen:
Kernel-Prozess
|
---- login
|
------- Shell
|
---------- ls
Wenn du jetzt zufaellig ein sehr langes ls hast ;-), und du killst
die Shell, weil es dir zu lange dauert, dann wird der SIGTERM (oder
auch SIGKILL) nicht nur an die Shell geschickt, sondern auch an das
ls. Dasselbe passiert beim Apachen:
Kernel-Prozess
|
------- Haupt-Apache-Prozess
|
------- Kind-Apache fuer den Request
|
--------- CGI-Prozess
|
---------- Kind des CGI-Prozesses
Das Signal hangelt sich also durch von CGI-Prozess zum Kind des
CGI-Prozesses. Deshalb muessen wir einen Weg finden, um setsid aus
der Prozess-Gruppe herauszuloesen und einen vollwertigen, eigenen
Haupt-Prozess daraus machen. Das uebernimmt setsid. Nach der
erfolgreichen Verwendung von setsid saehe die Prozess-Struktur so
aus:
Kernel-Prozess
|
+------ Haupt-Apache-Prozess
| |
| ------- Kind-Apache fuer den Request
| |
| --------- CGI-Prozess
|
|
------- Kind des CGI-Prozesses
Theoretisch duerfte der Apache also kein Signal mehr an das Kind
schicken. Das ist der ganze 'Trick' bei der Sache.
Wer mehr will, soll sich 'Advanced Programming In The UNIX(TM)
Environment' kaufen ;-)
Gruesse,
CK
Hoi,
exit 0; # (2)
Tss, Fussnote 2 hab ich doch glatt vergessen...
Also:
(2) Hier wird der Haupt-Prozess beendet. Ein fork() musst du dir so
vorstellen:
Mutter-Prozess
beliebiger Code
.
.
.
fork()
ab hier sind aus dem Mutter-Prozess zwei Prozesse geworden: Parent-
und Child-Prozess. Beide(!!) fuehren erstmal grundsaetzlich denselben
Code aus, der Kind-Prozess ist lediglich eine komplette Kopie des
Mutter-Prozesses. Das muss der Programmierer abfangen. Dazu muss man
wissen, dass $pid im Mutter-Prozess die PID (Prozess-ID) des Kindes
enthaelt und der Child-Prozess 0 enthaelt.
Wichtig zu fork zu wissen waere vielleicht noch, dass du im
Haupt-Prozess (sofern du nicht mit setsid() einen neuen Haupt-Prozess
machst) auf den Kind-Prozess warten solltest (per wait()), weil du
sonst Zombies erzeugen kannst. Zombies sind Prozesse, die im Grunde
schon beendet sind: sie belegen keinerlei Ressourcen mehr, koennen
sich aber auch nicht endgueltig beenden, weil ihnen das OK vom
Kernel dazu fehlt.
Gruesse,
CK
Hallo Christian,
ein dickes DANKE für Deine Erklärungen, so grob war mir das Verhältnis parent - child - Prozess schon klar, nur wie ich zu einem child komme - also so rein programmtechnisch in Perl ;-) - das hatte ich mir noch nie angesehen. Jetzt werde ich damit ein wenig rumprobieren und dann mein CGI-Script entsprechend ändern.
Kernel-Prozess
|
+------ Haupt-Apache-Prozess
| |
| ------- Kind-Apache fuer den Request
| |
| --------- CGI-Prozess (1)
|
|
------- Kind des CGI-Prozesses (2)
Wenn ich mir das so ansehe, kommt aber doch noch eine Frage: Der Apache erwartet vom CGI-Script eine Ausgabe, sonst produziert er den beliebten 500er. Ich warte also im Parent-CGI-Prozess (1) auf das Ende des Child (2), mache dann meine Ausgabe und beende mit exit. Richtig?
Gruß Frank
Hoi,
ein dickes DANKE für Deine Erklärungen, so grob war mir das
Verhältnis parent - child - Prozess schon klar
Dir vielleicht, aber anderen evntl. nicht.
Kernel-Prozess
|
+------ Haupt-Apache-Prozess
| |
| ------- Kind-Apache fuer den Request
| |
| --------- CGI-Prozess (1)
|
|
------- Kind des CGI-Prozesses (2)
Wenn ich mir das so ansehe, kommt aber doch noch eine Frage: Der
Apache erwartet vom CGI-Script eine Ausgabe, sonst produziert er
den beliebten 500er. Ich warte also im Parent-CGI-Prozess (1) auf
das Ende des Child (2), mache dann meine Ausgabe und beende mit
exit. Richtig?
Nein ;-)
Der Child ist hier kein Child mehr. Du machst im Haupt-Prozess
deine Ausgabe und beendest ihn dann, ohne Ruecksicht auf Verluste.
Gruesse,
CK