CGI Tutorial - Teil 6 / 10
Wolfgang Wiese (www.xwolf.de, xwolf@xwolf.de), Juli 1998, Letzte Änderung: Mai 2003[Das Common Gateway Interface]
[Übergabe von Benutzereingaben]
[Decodierung der übergebenen Daten]
[Schritt 1: Erstellung einer Eingabeform]
[Schritt 2: Die Programmierung]
[Schritt 3: Debugging eines CGI-Programmes]
[Standardfehler]
[Die Optimierung von CGI-Programmen durch Libraries und Module]
[Tipps, Tricks und Beachtenswertes]
[Links zu wichtigen FAQs und CGI-Seiten]
Schritt 3: Debugging eines CGI-Programmes
Bevor ich auf die Standardfehler eingehe, die CGI-Programmierer wiederfahren, erst einmal zu den
Fehlern, die konzeptionell bedingt sind und normalerweise unerwähnt bleiben.
Das obige Beispielprogramm funktioniert und scheint auch keine Probleme zu machen. Dennoch besitzt es
einen Fehler, welches dieses einfache und anscheinend harmlose Programm zur Falle machen kann!
In den meisten Fällen wird dieses Programm keine Probleme machen. Der Webmaster, der es geschrieben hat,
kann sich zurücklehnen und an nichts Böses denken. Und dann, vielleicht nachdem das Programm
mehr als ein Jahr fehlerfrei gelaufen ist, schnappt die Falle zu!
Plötzlich bläht sich die Datendatei auf und sprengt jede Speichergrenze. Bevor dies entdeckt wird,
ist meistens die Festplatte voll, oder aber der Prozessor versinkt ins Nirvana, weil es anscheinend einen
inkonsistenten Prozess bearbeitet.
Was ist geschehen?
Was leider oft vergessen wird, ist, das wir uns bei der CGI-Programmierung auf Systemen bewegen, auf
denen zur selben Zeit mehrere Benutzer arbeiten können, wo also auch viele Prozesse gleichzeitig
nebeneinander laufen.
Beim Absenden der Eingabeform durch einen Besucher der Webseite wird ein Prozess gestartet. Also das
CGI-Programm, welches wir oben entwickelt haben. Falls nur selten Besucher kommen, macht dies keine Probleme.
Ab einer bestimmten Besuchsrate jedoch kann es passieren, daß plötzlich 2 oder mehr Prozesse
zur selben Zeit versuchen wollen, auf die Datendatei zu schreiben.
Die Folgen können über die Zerstörung von Daten bis zum Endloslaufen eines Prozesses gehen.
Wenn Sie sich das nicht vorstellen können, denken Sie einfach mal an eine Diskussionsrunde, wo ein
Protokollant alles mitnotiert. Plötzlich wird die Diskussionsrunde hitziger und anstelle, daß
nur einer redet, sprechen plötzlich zwei oder mehr Leute durcheinander.
Folge: Der Protokollant wird sich mehrfach verschreiben, nicht mehr mitkommen, wahrscheinlich einige Sätze
falsch aufschreiben und durchstreichen oder den ganzen Zettel rausreissen und zerknüllen.
Und irgendwann wird er einfach aufgeben und es lassen alles niederzuschreiben, oder aber seinen Schuh ausziehen und
so lange auf den Tisch vor ihn eindreschen, bis wieder Ruhe ist...
Wenn man also ein CGI-Programm hat, welches auf gemeinsame Objekte (Dateien) zugreift, muß dafür
gesorgt werden, daß keine gleichzeitigen schreibenden Zugriffe auf Dateien geschehen können.
Die Informatik liefert hierzu einige gute Lösungsansätze.
(Die Stichworte lauten: Semaphoren, Busy Wait, Monitore, ..) Leider
sind kaum gute, allgemeinverständliche Dokumentationen hierzu zu finden, und
noch viel weniger konkrete Beispiele. (Anscheinend ist dieses Problem noch nicht so bekannt geworden,
da viele Benutzer noch von Einzelplatzrechnern ausgehen.)
Der folgende Code zeigt eine relative einfache Möglichkeit, dieses Problem unter Perl
(auf Unix- oder Linux-Systemen!!) zu lösen:
# Inter values for flock().
$LOCK_SH = 1;
$LOCK_EX = 2;
$LOCK_NB = 4;
$LOCK_UN = 8;
sub lock {
local($fh) = @_;
flock($fh,$LOCK_EX);
# and, in case someone appended
# while we were waiting...
seek($fh, 0, 2);
}
sub unlock {
local($fh)=@_;
flock($fh,$LOCK_UN);
}
Wird eine Datei zum Schreiben geöffnet wird die Datei gelockt. Dies hat zur Folge, daß
kein anderer Lesender oder Schreibender Prozess auf diese Datei zugreifen kann; Trifft ein open()
auf eine gelockte Datei, wartet dieses so lange, bis die Datei geunlockt wurde und öffnet erst
dann die Datei.
Nachdem der Prozess, der die Datei gelockt hat, fertig ist, ruft er unlock() auf.
Das obige CGI-Programm sieht dann so aus: (Nur der Teil, der die Datei schreibt)
...
open(filehandle,">>$dateiname")
|| &Fehlermeldung("Kann die Datei $dateiname nicht öffnen!");
&lock(filehandle);
print filehandle "-------Neuer Eintrag-------\n";
print filehandle "Lernerfolg = $in{'Lernerfolg'}\n";
print filehandle "Tempo = $in{'Tempo'}\n";
print filehandle "Vorkenntnisse = $in{'Vorkenntnisse'}\n";
print filehandle "Kommentar: $in{'Kommentar'}\n\n";
&unlock(filehandle);
close filehandle;
print "</HTML>\n";
# Wir schliessen das HTML-Dokument
exit(0);
...
Die Subroutinen lock() und unlock() fügen wir wieder am Ende des Programmes an. Oder
wir benutzen eine Library bzw. ein Modul. Doch dazu im nächsten Kapitel.
(Anmerkung zu flock(): Bitte beachten Sie, daß es selbst mit der sauberen Benutzung
von flock() unter Unix zu Zugriffskonflikten kommen kann, wenn der Webserver und das CGI-Programm auf
unterschiedlichen Partitionen liegen. flock() verhält sich über Mounting Points instabil.
Anstelle flock() alleine, sollte man dieses deshalb ggf. mit Softwarelinks verknüpfen.
Unter Windows ist flock() leider fast völlig untauglich.)
Info
$Id: cgitutor6.shtml,v 1.2 2003/05/20 20:55:32 xwolf Exp $
© 1996 - 2003 by xwolf -
xwolf ist eingetragene Marke beim Deutschen Patent- und Markenamt (Nr. 301 04 380)


