Calocybe: Perl-Prozesse synchronisieren - oder: Wie baue ich einen Counter?

Hallo! Ich mache gerade meine ersten Gehversuche im Thema CGI/Perl, und zu diesem Zweck baue ich einen Schmalspur-Counter. Dazu will ich in einer Textdatei mitzaehlen, wieviele Hits jede Seite hat. Wird das Script aufgerufen, soll es die Textdatei einlesen, den Wert aus der entsprechenden Zeile nehmen, um eins erhoehen, den Wert an den Browser zurueckschicken, und die Datei mit dem neuen Wert aktualisieren. Klar, was ich meine?
So, nun habe ich da zwei Probleme:

1.  Ich muss feststellen, von welcher HTML-Datei aus der Counter aufgerufen wird. Ich dachte, das koennte ich mit der ENV-Variable HTTP_REFERER erledigen, aber das klappt nicht. Diese Variable ist nur gesetzt, wenn ich das Perl-Skript direkt aufrufe, also von einer HTML-Datei einen Hyperlink auf das Script, dann ist der Referrer eben diese HTML-Datei. Wenn ich aber in einer HTML-Datei mittels
<SCRIPT LANGUAGE="JavaScript" SRC="/cgi-bin/counter.pl" TYPE="text/javascript"></SCRIPT>
das Ding aufrufe, ist HTTP_REFERER nicht gesetzt. Vielleicht sollte ich noch dazusagen, dass der verwendete Webserver der Microsoft IIS 3 ist.

2.  Wenn ich dann das Problem mit dem Referrer geloest habe, stehe ich vor einem neuen: Nehmen wir mal an, dass zwei HTML-Seiten fast gleichzeitig aufgerufen werden, und dann fast gleichzeitig der Counter aufgerufen wird, dann laufen doch zwei Perl-Prozesse unabhaengig voneinander, oder? Dann kann es passieren, dass die beiden sich bei ihrem Datei-Lesen/Schreiben in die Quere kommen, und im schlimmsten Fall die ganze counter.dat zerschiessen. Man muesste also die Prozesse irgendwie synchronisieren, damit sie nicht gleichzeitig auf die Datei zugreifen.

Also Leute, Ihr seid gefragt!

Calocybe

  1. Hi,

    1.  Ich muss feststellen, von welcher HTML-Datei aus der Counter aufgerufen wird.

    ich habe das bei mir gelöst, indem ich einfach counter.pl?page=Seitenname aufrufe. Den Seitennamen setze ich so, wie ich will, also nicht als URL. Das macht die Zeilen in der Zählerdatei nebenbei noch kürzer. Wie man das mit der aufrufenden Datei macht kann ich Dir leider auch nicht sagen, aber ein Counter (inzwischen countermania.de) hatte das mal versucht und arge Probleme damit gehabt, weil einige Browser den HTML-Referrer zurücklieferten, also das was document.referrer ist. Wenn Du einen Parameter benutzt ist der Code zwar nicht so einfach in andere Seiten zu kopieren, aber es funktioniert alles besser...

    2.  Wenn ich dann das Problem mit dem Referrer geloest habe, stehe ich vor einem neuen: Nehmen wir mal an, dass zwei HTML-Seiten fast gleichzeitig aufgerufen werden, und dann fast gleichzeitig der Counter aufgerufen wird, dann laufen doch zwei Perl-Prozesse unabhaengig voneinander, oder? Dann kann es passieren, dass die beiden sich bei ihrem Datei-Lesen/Schreiben in die Quere kommen, und im schlimmsten Fall die ganze counter.dat zerschiessen. Man muesste also die Prozesse irgendwie synchronisieren, damit sie nicht gleichzeitig auf die Datei zugreifen.

    Oh, ein leidiges Thema... Also, folgendes Verfahren ist ausgetestet und relativ sicher, aber eben auch nicht absolut:

    1.) Vor dem Lesen der Datei $filename prüfst Du
        while (-e "$filename.flock" && $flockcount < 5000) { $flockcount++; }
    2.) Vor dem Schreiben der Datei $filename erstellst Du $filename.flock mit einem Dummy-Wert:
        open(FLOCK,"$filename.flock");
        print FLOCK "1";
        close(FLOCK);
    3.) Nach dem Schließen der Datei $filename führst Du system("rm $filename.flock") aus.

    Nach Punkt 1 kannst Du noch prüfen, ob $flockcount den Wert 5000 erreicht hat. In dem Fall ist die Datei $filename.flock vermutlich durch einen Systemabbruch fehlerhaft noch existent, aber Du kannst auch auf eine Fehlerausgabe verzweigen. Vergiß nicht, vor der while-Schleife die $flockcount auf 0 zu setzen.

    Wie gesagt funktioniert das ganze recht gut bei mir, und zwar bei ziemlich starken Einsatz (durchschnittlich(!) alle 30 Sekunden für die selbe Datei). Wenn Du alle Dateizugriffe mit diesem System versiehst, sollte Deine Zählerdatei also sicher sein. Zusätzlich kannst Du aber noch beispielsweise ein mal täglich ein Backup der Datei machen.

    Viel Glück, und halt mich bitte über Deine Fortschritte auf dem Laufenden :-)

    Cheatah

    1. Hallo Cheatah!

      Irgendwie habe ich schon erwartet, dass Du es sein wuerdest, der (als erstes) eine Antwort schreibst - Vielen Dank. :-)

      ich habe das bei mir gelöst, indem ich einfach counter.pl?page=Seitenname aufrufe.

      Ja, die Idee hatte ich auch schon, und nun werde ich es auch so machen, aber schoen ist es nicht :-(  Denn wenn man den Aufruf-Code von einer in die andere HTML-Datei kopiert, darf man nicht vergessen, die Zeile anzupassen. Und wenn Du Deine Counter rumreichst, besteht doch immer die Gefahr, dass mal zwei Leute denselben Identifier angeben, oder?

      Wie man das mit der aufrufenden Datei macht kann ich Dir leider auch nicht sagen, aber ein Counter (inzwischen countermania.de) hatte das mal versucht und arge Probleme damit gehabt, weil einige Browser den HTML-Referrer zurücklieferten, also das was document.referrer ist.

      Ja, meiner offensichtlich auch (NS 4.08). Aber bei GeoCities scheint es sehr gut zu funktionieren.

      2. [...] Nehmen wir mal an, dass zwei HTML-Seiten fast gleichzeitig aufgerufen werden, und dann fast gleichzeitig der Counter aufgerufen wird, dann laufen doch zwei Perl-Prozesse unabhaengig voneinander, oder? [...]

      Oh, ein leidiges Thema...

      Ja, das ist sicher schonmal jemandem vor mir aufgefallen...

      1.) Vor dem Lesen der Datei $filename prüfst Du
          while (-e "$filename.flock" && $flockcount < 5000) { $flockcount++; }
      2.) Vor dem Schreiben der Datei $filename erstellst Du $filename.flock mit einem Dummy-Wert:
          open(FLOCK,"$filename.flock");
          print FLOCK "1";
          close(FLOCK);
      3.) Nach dem Schließen der Datei $filename führst Du system("rm $filename.flock") aus.

      Werden Variablen ($filename) also auch *innerhalb* von Anfuehrungszeichen aufgeloest? Das gibt es in keine anderen Sprache... (Ok, ich kenne natuerlich nicht alle auf der Welt). Oder hast Du das jetzt nur so zum Zeigen hingeschrieben? (Ich probier's aus)
      OK. Sieht gut aus, aber so ist die Sache verdammt abhaengig von der Geschwindigkeit des Systems. Ich wuerde etwas, wie sleep() einbauen, aber die kleinste Aufloesung ist dort 1 ganze Sekunde (eine Ewigkeit!). Und zu 3.) Das geht doch sicher nur auf einem UNIX-Rechner, bei MS heisst es doch DEL. Aber es gibt da auch eine Perl-Funktion - unlink() - wie ich gesehen habe.

      Nach Punkt 1 kannst Du noch prüfen, ob $flockcount den Wert 5000 erreicht hat. In dem Fall ist die Datei $filename.flock vermutlich durch einen Systemabbruch fehlerhaft noch existent,

      Naja, oder der Server-Rechner war zu schnell.

      Viel Glück, und halt mich bitte über Deine Fortschritte auf dem Laufenden :-)

      OK, ich melde mich, wenn ich fertig bin - oder wieder Fragen habe :-)

      Thanx, Calocybe

      1. Hi!

        Werden Variablen ($filename) also auch *innerhalb* von Anfuehrungszeichen aufgeloest? Das gibt es in keine anderen Sprache... (Ok, ich kenne natuerlich nicht alle auf der Welt). Oder hast Du das jetzt nur so zum Zeigen hingeschrieben? (Ich probier's aus)

        "In solchen Anführungszeichen werden Variablen expandiert",
        'in solchen dagegen nicht'!
        Dieses Verhalten ist IMHO auch in Unix-Shell-Skripten zu beobachten...

        Viele Grüße

        Andreas Bierhals

      2. Hi,

        Irgendwie habe ich schon erwartet, dass Du es sein wuerdest, der (als erstes) eine Antwort schreibst - Vielen Dank. :-)

        :-)

        ich habe das bei mir gelöst, indem ich einfach counter.pl?page=Seitenname aufrufe.
        Ja, die Idee hatte ich auch schon, und nun werde ich es auch so machen, aber schoen ist es nicht :-(  Denn wenn man den Aufruf-Code von einer in die andere HTML-Datei kopiert, darf man nicht vergessen, die Zeile anzupassen. Und wenn Du Deine Counter rumreichst, besteht doch immer die Gefahr, dass mal zwei Leute denselben Identifier angeben, oder?

        Jepp, die Problematik stimmt so. Ich habe mir darüber auch meine Gedanken gemacht, weil ich derzeit ebenfalls einen Counter programmiere, aber die Parameter-Lösung blieb immer als einziges über. Aber warum willst Du den Counter rumreichen? Als Counterprovider? Dann empfehle ich noch den Parameter id ;-)

        Ja, meiner offensichtlich auch (NS 4.08). Aber bei GeoCities scheint es sehr gut zu funktionieren.

        GeoCities macht das vermutlich über Serverkonfigurationen. Schließlich steht ja auch einiges im Logfile... und man kann so dies und das nutzen, wie man an Xoom-Grafiken sieht!

        Oh, ein leidiges Thema...
        Ja, das ist sicher schonmal jemandem vor mir aufgefallen...

        *lol* :-)

        Werden Variablen ($filename) also auch *innerhalb* von Anfuehrungszeichen aufgeloest? Das gibt es in keine anderen Sprache... (Ok, ich kenne natuerlich nicht alle auf der Welt). Oder hast Du das jetzt nur so zum Zeigen hingeschrieben? (Ich probier's aus)

        Siehe Andreas' Antwort - innerhalb von "Doublequotes" werden sie aufgelöst, innerhalb von 'Singlequotes' nicht.

        OK. Sieht gut aus, aber so ist die Sache verdammt abhaengig von der Geschwindigkeit des Systems. Ich wuerde etwas, wie sleep() einbauen, aber die kleinste Aufloesung ist dort 1 ganze Sekunde (eine Ewigkeit!).

        Erhöhe einfach den Wert 5000 auf 10000 oder so, aber eigentlich sollte das reichen. Du kannst auch die Prüfung $flockcount < x einfach weglassen und darauf vertrauen, daß die Datei immer korrekt gelöscht wird.

        Und zu 3.) Das geht doch sicher nur auf einem UNIX-Rechner, bei MS heisst es doch DEL. Aber es gibt da auch eine Perl-Funktion - unlink() - wie ich gesehen habe.

        Ja, 'tschuldigung, aber hauptsache es wird gelöscht :-)
        unlink() gibt es auch, aber Dateioperationen aller Art (auch mkdir etc.) mache ich persönlich lieber über system(). Keine Ahnung warum, aber ich betrete lieber bekannte Wege.

        Nach Punkt 1 kannst Du noch prüfen, ob $flockcount den Wert 5000 erreicht hat. In dem Fall ist die Datei $filename.flock vermutlich durch einen Systemabbruch fehlerhaft noch existent,
        Naja, oder der Server-Rechner war zu schnell.

        :-)

        Viel Glück, und halt mich bitte über Deine Fortschritte auf dem Laufenden :-)
        OK, ich melde mich, wenn ich fertig bin - oder wieder Fragen habe :-)

        Alles klar, wir werden dann sehen!

        Cheatah

        1. Hi,

          Jepp, die Problematik stimmt so. Ich habe mir darüber auch meine Gedanken gemacht, weil ich derzeit ebenfalls einen Counter programmiere, aber die Parameter-Lösung blieb immer als einziges über. Aber warum willst Du den Counter rumreichen? Als Counterprovider? Dann empfehle ich noch den Parameter id ;-)

          Nein, nicht ICH. Ich meinte DICH! Du willst doch Deine Counter anbieten? Ich mache das nur fuer unseren kleinen Server im Intranet, und da bin ich der Herrscher.

          Calocybe

          1. Hi,

            Nein, nicht ICH. Ich meinte DICH! Du willst doch Deine Counter anbieten? Ich mache das nur fuer unseren kleinen Server im Intranet, und da bin ich der Herrscher.

            ach so :-)
            Ja, ich will meinen Counter anbieten. Da gibt es aber mehrere Parameter:
            id = Benutzername,
            counter = Countername (kann sich bei verschiedenen Benutzern wiederholen),
            page = Seitennamen (kann sich bei verschiedenen Countern und/oder Benutzern wiederholen).

            Auf diese Weise habe ich da eigentlich wenig Probleme mit... :-) Aber danke für Deine Sorge!

            Cheatah

          2. Offenbar spielt das Forum in letzter Zeit etwas verrueckt. Dieser Beitrag ist wieder zweimal zu lesen, einmal da wo es hingehoert im Thread "Perl-Prozesse synchronisieren - oder: Wie baue ich einen Counter?" als Antwort auf Cheatah, und einmal im Thread "GIF und Perl", wo ich mir angeblich selbst antworte. Beide Links zeigen auf die 8366.html. Soetwas gab's vor kurzem schonmal im Thread "ZENSUR bei Internet Magazin???" wo mein Beitrag auch zweimal gepostet wurde, einmal mit meinem Namen, einmal mit dem von Andre.
            Stefan, kannst Du mal eben das Script korrigieren?

            Calocybe

            1. Hi,

              das Script verhält sich eigentlich normal... es liest bei einer Antwort das HTML-File zeilenweise ein und prüft, ob ein bestimmtes Codewort mit der Nummer des Artikels, auf den man geantwortet hat, auftaucht. Durch den Fehler taucht dieses Codewort jetzt aber zweimal auf, deshalb wird der Artikel auch zweimal eingebunden...

              Stefan, kannst Du mal eben das Script korrigieren?

              Ich unterstütze den Antrag *grins*
              Naja, jetzt wollen wir ihn mal nicht drängen, er hat ja schon zugesagt. Die Sache mit den doppelten Antwortartikeln wird er aber auch nicht ändern können, dazu muß er die Technik komplett umorganisieren.

              Cheatah

    2. hi!

      3.) Nach dem Schließen der Datei $filename führst Du system("rm $filename.flock") aus.

      Die Perl-Funktion zum Löschen von Dateien heißt unlink. Und von der Funktion flock hast du auch noch nie gehört? ;))

      bye, Frank!

      1. Hi,

        Die Perl-Funktion zum Löschen von Dateien heißt unlink. Und von der Funktion flock hast du auch noch nie gehört? ;))

        wie gesagt, jeder hat so seine Vorlieben... und was flock betrifft, siehe oben ;-)

        Cheatah

    3. Hallo auch!

      Oh, ein leidiges Thema... Also, folgendes Verfahren ist ausgetestet und relativ sicher, aber eben auch nicht absolut:

      1.) Vor dem Lesen der Datei $filename prüfst Du
          while (-e "$filename.flock" && $flockcount < 5000) { $flockcount++; }
      2.) Vor dem Schreiben der Datei $filename erstellst Du $filename.flock mit einem Dummy-Wert:
          open(FLOCK,"$filename.flock");
          print FLOCK "1";
          close(FLOCK);
      3.) Nach dem Schließen der Datei $filename führst Du system("rm $filename.flock") aus.

      Wie gesagt funktioniert das ganze recht gut bei mir, und zwar bei ziemlich starken Einsatz (durchschnittlich(!) alle 30 Sekunden für die selbe Datei). Wenn Du alle Dateizugriffe mit diesem System versiehst, sollte Deine Zählerdatei also sicher sein. Zusätzlich kannst Du aber noch beispielsweise ein mal täglich ein Backup der Datei machen.

      Die von mir verwendete Variante schaut doch ziemlich ähnlich aus - aber nur fast. Bei meinen Überlegungen kam mal so die Frage auf, was denn nun passiert, wenn zwei Prozesse gleichzeitig sehen, daß die *.flock Datei NICHT existier. In diesem Falle würden beide gleichzeitig davon ausgehen, die gesperrte Datei nutzen zu können ...

      Wie aber kann ich sicherstellen, daß nur ein Prozess zur Zeit eine flock-Datei anlegt??? Oder allgemeiner gesagt - nur ein Prozess soll den Status auf locked ändern können.

      Meine Idee war nun, daß das löschen einer Datei nur einmal (korrekt) auftreten kann. Die Perl-eigene Funktion zum löschen von Dateien (unlink) gibt glücklicherweise zurück, wieviele der angegebenen Dateien gelöscht wurden! Die geänderte Variante würde also ungefähr wie folgt ausschauen:

      1.) Vor dem Lesen der Datei $filename prüfst Du
          while (!-e "$filename.noflock" && $flockcount < 5000) { $flockcount++; }
      2.) Vor dem Schreiben der Datei $filename löscht Du $filename.noflock
          if (unlock("$filename.noflock"))
          {
              [...]
          }
      3.) Nach dem Schließen der Datei $filename führst Du system("touch $filename.noflock") aus.

      So ähnlich jedenfalls. Man sollte hier natürloch noch den Fall abfangen, daß die Datei nicht gelöscht werden konnte. In diesem Falle könnte man z.B. einfach wieder von vorne anfangen.

      Zum Schluß noch eine Anmerkung: Das warten, welches Cheatah hier einsetzt ist ziemlich aktiv (busy waiting). hier sollte man wohl ein sleep mit in die Schleife setzen, so daß man das Heft regelmäßig an das Betriebssystem abgibt ...

      Jörk

      1. Hallo auch!

        Die von mir verwendete Variante schaut doch ziemlich ähnlich aus - aber nur fast. Bei meinen Überlegungen kam mal so die Frage auf, was denn nun passiert, wenn zwei Prozesse gleichzeitig sehen, daß die *.flock Datei NICHT existier. In diesem Falle würden beide gleichzeitig davon ausgehen, die gesperrte Datei nutzen zu können ...

        Ja, habe ich mir auch schon gedacht, haette es aber vorruebergehend in Kauf genommen. Je schneller der Server-Rechner ist (unserer ist immerhin ein Double-Prozessor-System der 6. Generation), um so schneller sollte auch die Abfragerei erledigt sein. Und um so unwahrscheinlicher ist es, dass sich zwei Prozesse genau an dieser Stelle in die Quere kommen.

        Wie aber kann ich sicherstellen, daß nur ein Prozess zur Zeit eine flock-Datei anlegt??? Oder allgemeiner gesagt - nur ein Prozess soll den Status auf locked ändern können.

        Meine Idee war nun, daß das löschen einer Datei nur einmal (korrekt) auftreten kann.

        Ja. Wirklich sicher kann man nur auf Betriebssystemebene synchronisieren.

        Die Perl-eigene Funktion zum löschen von Dateien (unlink) gibt glücklicherweise zurück, wieviele der angegebenen Dateien gelöscht wurden! Die geänderte Variante würde also ungefähr wie folgt ausschauen:
        1.) Vor dem Lesen der Datei $filename prüfst Du
            while (!-e "$filename.noflock" && $flockcount < 5000) { $flockcount++; }
        2.) Vor dem Schreiben der Datei $filename löscht Du $filename.noflock
            if (unlock("$filename.noflock"))
            {
                [...]
            }
        3.) Nach dem Schließen der Datei $filename führst Du system("touch $filename.noflock") aus.

        Hey super! Sieht gut aus! Natuerlich meinst Du bei 2.)  if (unlink(...)).  Und touch gibt es nur unter UNIX (siehe dazu meine Funktion weiter unten).

        So ähnlich jedenfalls. Man sollte hier natürloch noch den Fall abfangen, daß die Datei nicht gelöscht werden konnte. In diesem Falle könnte man z.B. einfach wieder von vorne anfangen.

        Man koennte nicht, man sollte. Aber nicht immer wieder, sondern nur eine max. Anzahl oft.

        Zum Schluß noch eine Anmerkung: Das warten, welches Cheatah hier einsetzt ist ziemlich aktiv (busy waiting). hier sollte man wohl ein sleep mit in die Schleife setzen, so daß man das Heft regelmäßig an das Betriebssystem abgibt ...

        Ja, leider ist die kleinste Aufloesung von Sleep allerdings 1 Sekunde. Naja, dass muessen wir wohl in Kauf nehmen.

        Gute Moeglichkeit, ich habe jedoch in die Richtung flock() weiterexperimentiert. Dabei bin ich im Moment so weit:

        sub GetCounterBaseControl() {
            my $i;

        if (! -e $counterbase) {
                open(CBASE, ">$counterbase");
                close(CBASE);
            }

        report "--Tryin' to open!\n";
            for ($i=0; (!open(CBASE, "+<$counterbase") && ($i < $cTIMEOUT)); $i++) { sleep(1) }
            abort() unless ($i < $cTIMEOUT);

        report "--Tryin' to lock!\n";
            for ($i=0; (!flock(CBASE, $cFLOCK_EXCLUSIVE|$cFLOCK_NOBLOCK) && ($i < $cTIMEOUT)); $i++) { sleep(1) }
        }

        $counterbase ist der Dateiname, report() ist eine verkappte print()-Funktion, abort() tut so aehnlich wie die (da ;-)), $cXXX sind selbstdefinierte "Konstanten".
        Ich habe zwei Prozesse aufeinanderrennen lassen, indem ich den einen gestartet habe, die Datei habe locken lassen, dann ein sleep(5), den anderen gestartet. Ergebnis: Der zweite Prozess fuehrt das open() durch (davor hatte Cheatah gewarnt!), die TimeOut-Schleife ist dort also sinnlos, aber vor dem Versuch, die Datei zu flocken, haelt er an, bis der erste die Datei wieder freigibt. Also Cheatah: Deine Warnung ist berechtigt. Halten sich aber alle zugreifenden Prozesse an ein gemeinsames Protokoll (das heisst hier "unbedingt flock mit Parameter $cFLOCK_EXCLUSIVE =$LOCK_EX = 2; durchfuehren"), bekommt man die Sache in den Griff.
        Die ersten Zeilen der Funktion legen die Datei an, falls sie noch nicht existiert (macht also dasselbe wie touch). Dort tritt natuerlich dasselbe Synchronisierungsproblem auf, das Du mit Deiner Methode gerade vermieden hast. Aber wenn die Counterdatei schon existiert, was sie ja normalerweise tut, ist das auch egal.

        Danke fuer Eure Mithilfe, habe einiges gelernt!
        Calocybe

  2. hi!

    <SCRIPT LANGUAGE="JavaScript" SRC="/cgi-bin/counter.pl" TYPE="text/javascript"></SCRIPT>

    So kannst du doch kein Perl-Skript einbinden. Diese Syntax funktioniert für externe JavaScripts. Du musst entweder das Perl-Skript über ein <img>-Tag oder per SSI einbinden, damit der HTTP_REFERRER funktioniert.

    gleichzeitig auf die Datei zugreifen.

    Alternativ zu Cheatahs Methode könntest du die Perl-Funktion flock verwenden, um die Datei zu sperren. Dann kann nur der aktuelle Prozess darauf zugreifen, die anderen erhalten bei der Ausführung von flock eine Fehlermeldung.

    bye, Frank!

    1. Hi,

      Alternativ zu Cheatahs Methode könntest du die Perl-Funktion flock verwenden, um die Datei zu sperren. Dann kann nur der aktuelle Prozess darauf zugreifen, die anderen erhalten bei der Ausführung von flock eine Fehlermeldung.

      von flock rate ich ab! Damit kann man eine Datei zwar vor Schreibzugriffen schützen, aber nicht vor LESEzugriffen! Und wenn nun gerade eine Datei zum Schreiben geöffnet wird, ist sie zunächst einmal leer... wird sie danach gelesen, hat das Script leere Daten, die es anschließend in die ge-unflockte Datei schreibt. Folge: kompletter Datenverlust!

      Natürlich kann flock zusätzlich verwendet werden, aber durch das konsequente Schützen vor Lesezugriffen sollte eigentlich auch kein paralleler Schreibzugriff auftreten.

      Cheatah

      1. hi!

        von flock rate ich ab! Damit kann man eine Datei zwar vor
        Schreibzugriffen schützen, aber nicht vor LESEzugriffen!

        Du kannst die Datei ja auch vor dem Lesen mit flock sperren, dann hast du dieses Problem nicht.

        bye, Frank!

        1. Hi,

          Du kannst die Datei ja auch vor dem Lesen mit flock sperren, dann hast du dieses Problem nicht.

          auch wenn sie bereits vor einem Schreibzugriff geflockt wurde? In dem Fall würde meiner Erfahrung nach flock einfach übergangen werden, weil die Datei ja schon geflockt ist. Sie ist aber leer und wird leer gelesen - und später leer geschrieben.

          Cheatah

          1. hi!

            Du kannst die Datei ja auch vor dem Lesen mit flock sperren, dann hast du dieses
            Problem nicht.
            auch wenn sie bereits vor einem Schreibzugriff geflockt wurde? In dem Fall würde meiner
            Erfahrung nach flock einfach übergangen werden, weil die Datei ja schon geflockt ist. Sie ist
            aber leer und wird leer gelesen - und später leer geschrieben.

            Nein, du kannst anhand des Rückgabewertes von flock überprüfen, ob bereits ein anderer Prozess die Datei geflockt hat, zb.:
              while (flock ...) {}
            Das erzeugt solang eine Pause im Programm, bis die Datei gesperrt werden kann. Oder:
              while ((flock ...) || ($i++ < ...)) {}

            bye, Frank!

            1. Hi,

              Nein, du kannst anhand des Rückgabewertes von flock überprüfen, ob bereits ein anderer Prozess die Datei geflockt hat, zb.:
                while (flock ...) {}
              Das erzeugt solang eine Pause im Programm, bis die Datei gesperrt werden kann. Oder:
                while ((flock ...) || ($i++ < ...)) {}

              hm... ich habe mal mit zwei anderen, die ein ähnliches Problem hatten wie ich, recht lange eine sichere Methode gesucht. Ich erinnere mich, daß einer diese Lösung mal erwähnte, sie aber auch als unsicher abgetan hat. Hat er sich wohl geirrt?

              Danke aber für die Ausführungen!

              Cheatah

    2. hi!

      <SCRIPT LANGUAGE="JavaScript" SRC="/cgi-bin/counter.pl" TYPE="text/javascript"></SCRIPT>

      So kannst du doch kein Perl-Skript einbinden. Diese Syntax funktioniert für externe JavaScripts. Du musst entweder das Perl-Skript über ein <img>-Tag oder per SSI einbinden, damit der HTTP_REFERRER funktioniert.

      Doch, das geht. Habe ich schon ausprobiert:
          print "Content-type: text/javascript\n\n";
          print "var counter = 12345;\n"
      An der entsprechenden Stelle im HTML einfach document.write(counter); und die Sache passt. Allerdings ist das vielleicht der Grund, warum HTTP_REFERER nicht funktioniert (wird mit einem R geschrieben, obwohl das englische Wort referrer zwei solche in der Mitte hat). Dann frage ich mich wieder mal, WARUM wird diese Information einmal mitgesendet und einmal nicht?

      Alternativ zu Cheatahs Methode könntest du die Perl-Funktion flock verwenden, um die Datei zu sperren. Dann kann nur der aktuelle Prozess darauf zugreifen, die anderen erhalten bei der Ausführung von flock eine Fehlermeldung.

      Cheatah raet davon ab, aber ich werd's mir auf jeden Fall mal anschauen.

      bye, Calocybe!

      1. Hi,

        Cheatah raet davon ab, aber ich werd's mir auf jeden Fall mal anschauen.

        also, ich habe mich vielleicht etwas mißverständlich ausgedrückt, deshalb noch mal zur Klarheit:
        Es spricht nichts gegen die Verwendung von flock, es gibt keine Gefahren durch die Verwendung des Befehls. Nur ist flock alles andere als sicher. Meine Methode ist wesentlich sicherer, und bei konsequentem Einsatz ist flock auch unnötig. Ich wollte nur davon abraten, sich auf flock zu verlassen :-)

        Cheatah

  3. Hallo,
    wenn du mit dem IIS3 arbeitest, dann mache es doch mit ASP. ASP besitzt eine Counter-Komponente mit Reloadschutz und es treten auch nicht die befürchteten Probleme auf. Das ganze braucht ganze zwei Programmzeilen.
    cu
    Thomas

    1. Hallo,

      wenn du mit dem IIS3 arbeitest, dann mache es doch mit ASP. ASP besitzt eine Counter-Komponente mit Reloadschutz und es treten auch nicht die befürchteten Probleme auf. Das ganze braucht ganze zwei Programmzeilen.

      Danke fuer den Tip - JEDOCH:

      1.  Ich weiss gar nicht, wie ASP funktioniert. Perl ist mir erstmal genug.

      2.  ASP ist von Microsoft, deshalb werde ich es im Zusammenhang mit dem Web nicht benutzen, solange ich das selbst entscheiden kann. (Den Webserver habe ich nicht selbst ausgesucht.) Die sind bei Microsoft tatsaechlich so arrogant, das asp zeug fuer den Standard im Web zu halten. Nun, ich habe da mal gehoert, dass stattdessen vereinzelt auch Perl-Scripts verwendet werden.

      3.  Werde ich keine fertigen Komponenten verwenden, solange es sich vermeiden laesst. Ich hasse es, etwas nicht unter Kontrolle zu haben. Und wenn in dem Counter-Ding ein Bug ist, kann ich ihn nicht beseitigen. Was fertiges Zeug und Templates und so betrifft, habe ich genuegend schlechte Erfahrungen mit den MFC-Klassen gemacht (immer wieder die Frage: "Sind die denn nur dumm dort bei MS?!") - da programmiere ich doch lieber direkt mit dem Win API, das ist einfach und verstaendlich, meistens jedenfalls.

      4.  Und vor allem bin ich mit Perl wesentlich kompatibler. Was ich ueber Perl lerne, kann ich bei jeder x-beliebigen Homepage verwende, solange der Provider CGI unterstuetzt. Und ASP? Wenn ich wirklich was schnelles, einfaches und inkompatibles will, dann schreib ich mir ein C-Programm. Windows NT bietet genuegend Synchronisationsmittel, mit denen ich meine Dateizugriffe kontrollieren kann (Critical Section, Mutex-Objekte, Semaphoren, ...).

      Das soll natuerlich nicht gegen Dich sein, nochmal danke fuer den Tip, jedoch gibt es gewisse Stellen, an denen besinne ich mich auf meine Prinzipien (die ich mir muehsam aus meiner Erfahrung aufgebaut habe).

      Calocybe

      1. Hallo,

        4.  Und vor allem bin ich mit Perl wesentlich kompatibler. Was ich ueber Perl lerne, kann ich bei jeder x-beliebigen Homepage verwende, solange der Provider CGI unterstuetzt. Und ASP? Wenn ich wirklich was schnelles, einfaches und inkompatibles will, dann schreib ich mir ein C-Programm. Windows NT bietet genuegend Synchronisationsmittel, mit denen ich meine Dateizugriffe kontrollieren kann (Critical Section, Mutex-Objekte, Semaphoren, ...).

        Ich weiss zwar nicht, auf welcher Betriebssystemplattform der WEB-Server Deines Providers läuft, aber auch unter UNIX gibt es Möglichkeiten mit Semaphoren zu arbeiten. Ich hab vor etwa zweieinhalb, drei Jahren mal einen Artikel über Semphoren mit Named-Pipes unter UNIX gelesen. Leider habe ich aber die Quelle nicht mehr im Kopf (dumm), weiss aber noch, wer mir damals den Artikel gegeben hat. Dieser nette Mensch war Dozent am b.i.b. in Bergisch-Gladbach. Zum Glück kann ich noch an die Adresse seiner HP kommen. Sie lautet: http://www.bg.bib.de/~dozae/. Seine E-Mail-Adresse ist:alenfelder@bg.bib.de. Vielleicht hilft Dir das etwas weiter.

        Michael N.

        1. Hallo,

          4.  [...] Windows NT bietet genuegend Synchronisationsmittel, mit denen ich meine Dateizugriffe kontrollieren kann (Critical Section, Mutex-Objekte, Semaphoren, ...).

          Ich weiss zwar nicht, auf welcher Betriebssystemplattform der WEB-Server Deines Providers läuft, aber auch unter UNIX gibt es Möglichkeiten mit Semaphoren zu arbeiten.

          Ich habe deshalb die Windows-NT-Mittel erwaehnt, weil eben das die Plattform "meines Providers" ist. (Mein Provider ist meine Firma - es handelt sich um ein Intranet.) Dass diese Mittel unter jedem Multitaskingsystem vorhanden sind, ist ja klar (Win95 schliesse ich hiermit explizit aus!). Bei UNIX gibt's das natuerlich schon viel laenger als bei NT.

          Zum Glück kann ich noch an die Adresse seiner HP kommen. Sie lautet: http://www.bg.bib.de/~dozae/. Seine E-Mail-Adresse ist:alenfelder@bg.bib.de. Vielleicht hilft Dir das etwas weiter.

          Wow! Die Page ist der Hammer! Jedenfalls fuer jemanden wie mich, der gierige Augen kriegt, wenn er sowas wie "Compilerbau" hoert. Schaetze, fuer die meisten ist das zu theoretisch.

          Calocybe