Katzenbauer
Erfahrenes Mitglied
Wie ich bereits hier angekündigt habe arbeite ich schon seit einiger Zeit an einer php Libary. Ich habe mich dazu entschieden das ganze Ding in eine Klasse zu packen, weil das mir am praktischsten erscheint. Leider verwende ich aus Kompatibilitätsgründen noch nicht die neuen PHP5 Schlüsselwörter (leider). Ich bin bisher nur sehr langsam voran gekommen, weil es da doch einige Knackpunkte gab wo man ziemlich lange dran knobelt, wenn man sich noch nicht so lange mit Netzwerkprogrammierung beschäftigt und das Teil dann erstmal frustriert für ein paar Tage in die Ecke schmeißt. Außerdem gibt es da noch einige sehr php spezifische Stolpersteine.
Zudem überarbeite ich das Teil stetig, verbessere Kommentare, Error Handling, weil ich vorhabe das Teil unter der GPL zu releasen und sich deshalb andere Programmierer darin effizient zurecht finden sollen. Und da der Code (meiner Meinung nach) nicht grade trivial ist möchte ich, dass mir das so gut wie möglich gelingt. Da es mein erstes OpenSource Projekt ist, habe ich mich bisher nie um Dokumentationen geschert. Ich habe beschlossen den PHPDocumentor zu benutzen. d.H Erstmal wieder die Kommentare erweitern/umstellen. Ich frage mich ob ich damit nur öffentliche Methoden (also die, die man auch wirklich braucht) oder auch die Methoden die nur innerhalb der Klasse verwendet werden, dokumentieren soll, weil der Anwender will ja nur das nötigste wissen und sich dann an die Arbeit machen. Aber ich denke das könnte man doch auch einfach nur mit einer etwas ausführlicheren Readme abdecken, oder?
Wie dem auch sei ich bin noch lange nicht fertig. Ich bin jetzt erst fast mit der Login-Funktion fertig und habe bei stetiger Optimierung schon > 600 Zeilen (allerdings inkl. Komentare). Bis man sinvoll Nachrichten verschicken kann verdoppelt sich das bestimmt noch.
Und da liegt auch schon der Knackpunkt. Ich mache mir im Moment Gedanken wie ich das sinvoll umsetzen kann, weil es gibt einige Punkte, die einem php Script Probleme bereiten.
Ein Problem stellt uns zunächst mal der Icq Server, der festlegt wieviele Logins, Nachrichten, etc. maximal in einer bestimmten Zeitspanne hintereinander gesendet werden können. Wenn man ein bestimmtes Limit überschreitet trennt der Server die Verbindung hart und sperrt die Benutzernummer für ein paar Minuten, was natürlich fatal wäre. Würde man dann noch weiter machen verlängert sich die Sperrzeit nur noch. Deshalb fällt folgende Implementierung z.B in einem stark frequentierten Browsergame weg, wenn z.B eine Icq Nachricht gesendet werden kann, wenn man angegriffen wird:
Wenn man nicht wegen der oft hintereinander folgenden Logins gekillt wird (was meistens schon nach 5 Stück passiert), dann, wenn man zuviele Nachrichten schickt. Dann werden Nachrichten, die man schickt einfach nicht mehr weitergeleitet.
Eine Lösung muss also her für dieses Problem. Das größte Problem ist bisher wie man es umgeht, dass man sich bei jedem Scriptaufruf neu einloggen muss. Wenn man eine Verbindung über fsockopen() aufbaut, dann wird diese automatisch nach Ende des Scriptaufrufs beendet und man müsste sich wieder neu einloggen. Eine mögliche Lösung ist die Funktion pfsockopen(). Sie hält die (Tcp) Verbindng auch nach Scriptausführung aufrecht (wenn man nicht fclose() macht). Das heißt, dass der Webserver auch nach Ablauf des Scriptes (also theorethisch 24/7) im Icq Online sein könnte und man so die Verbindung nur bei Bedarf neu aufbaut und man sich von da an nur noch um das Problem kümmern müsste wie man es veranlasst, dass nicht zu viele Nachrichten auf einmal geschickt werden (darauf komme ich später zurück).
Jedoch tuen sich bei einer permanenten Verbindung weitere Probleme auf. Wie stelle ich fest, dass schon eine Verbindung zum Icq Server besteht und ich direkt eine Nachricht senden kann ohne mich vorher einzuloggen? Also wie stelle ich fest, dass ich schon eingelogged bin. Auch habe ich manchmal das Problem, wenn die Verbindung nicht nach Scriptaufruf beendet (also permanent ist) wird (entweder durch pfsockopen() und kein fclose() oder das Script durch einen Error mittendrin abgebrochen wird (durch php) und er so nicht bis zum fclose() nicht kommt), dass dann noch irgendwelcher Müll im Stream-Buffer (ich nenn das mal so) befindet und sich dann, wenn man einen neuen Scriptaufruf macht der sich vor das neu Empfangene schiebt(natürlich steht es einfach nur davor weil es noch vom letzten Aufruf drinsteht) und so natürlich das Script zum Abruch bringt, weil diese Daten dann natürlich zu dem Zeitpunkt nicht erwartet werden und die Funktion abgebrochen wird. Vielleicht gibt es hier einen Spezialisten auf dem Gebiet, der mal was dazu sagen kann
Zu dem Problem, dass zu viele Nachrichten geschickt werden habe ich mir folgende Lösung überlegt:
Und zwar schickt der Server jedem Clienten (also auch meinem Script) beim einloggen ein Packet, welches für jeden Service Informationen enthält (Login, Nachrichten etc.) wie das sogenannte "Flow-Limit" festgelegt ist. Dieses wird im Moment noch nicht verwaltet, weil das fast 1KB Daten sind und das sehr sehr viel Arbeit wird das zu parsen und gescheit zu speichern. Da muss ich mich erstmal genauer mit beschäftigen.
Die Klasse könnte also bei jeder geschickten Nachricht das Flow-Limit überprüfen und, wenn noch neue Nachrichten geschickt werden können einfach die Nachricht abschicken ansonsten wird die Nachricht in eine Art Buffer geschrieben(Textdatei) und nichts passiert. Ein Cronjob könnte dann dafür sorgen, dass die Nachrichten abgeschickt werden. In dem befindet sich eine Schleife die, die Nachrichten im Buffer durchgeht und falls noch neue Nachrichten gesendet werden können die absendet (es muss halt nur dafür gesorgt werden, dass sie nicht zu schnell hintereinander geschickt werden). Für Seiten, die ein sehr großes Nachrichtenaufkommen haben könnte man dann mehre Accounts eintragen und der Cronjob wechselt dann den Account, wenn er zu viele Nachrichten geschickt hat (bevor der Account gemuted wird). Laufzeit des Scripts sollte man natürlich mit Zeitabstand zwischen den Aufrufen abstimmen, damit es einerseits fast immer läuft und andererseits nicht aufgerufen wird, wenn es bereits läuft.
Ihr seht ein ziemlich komplexes Thema. Wenn ihr Tipps habt oder euren Senf dazu abgeben wollt wie ihr es machen würdet dann bitte her damit, denn dafür habe ich dieses Posting erstellt. Ich hoffe es macht sich überhaupt jemand die Mühe und liest sich das durch.
Zudem überarbeite ich das Teil stetig, verbessere Kommentare, Error Handling, weil ich vorhabe das Teil unter der GPL zu releasen und sich deshalb andere Programmierer darin effizient zurecht finden sollen. Und da der Code (meiner Meinung nach) nicht grade trivial ist möchte ich, dass mir das so gut wie möglich gelingt. Da es mein erstes OpenSource Projekt ist, habe ich mich bisher nie um Dokumentationen geschert. Ich habe beschlossen den PHPDocumentor zu benutzen. d.H Erstmal wieder die Kommentare erweitern/umstellen. Ich frage mich ob ich damit nur öffentliche Methoden (also die, die man auch wirklich braucht) oder auch die Methoden die nur innerhalb der Klasse verwendet werden, dokumentieren soll, weil der Anwender will ja nur das nötigste wissen und sich dann an die Arbeit machen. Aber ich denke das könnte man doch auch einfach nur mit einer etwas ausführlicheren Readme abdecken, oder?
Wie dem auch sei ich bin noch lange nicht fertig. Ich bin jetzt erst fast mit der Login-Funktion fertig und habe bei stetiger Optimierung schon > 600 Zeilen (allerdings inkl. Komentare). Bis man sinvoll Nachrichten verschicken kann verdoppelt sich das bestimmt noch.
Und da liegt auch schon der Knackpunkt. Ich mache mir im Moment Gedanken wie ich das sinvoll umsetzen kann, weil es gibt einige Punkte, die einem php Script Probleme bereiten.
Ein Problem stellt uns zunächst mal der Icq Server, der festlegt wieviele Logins, Nachrichten, etc. maximal in einer bestimmten Zeitspanne hintereinander gesendet werden können. Wenn man ein bestimmtes Limit überschreitet trennt der Server die Verbindung hart und sperrt die Benutzernummer für ein paar Minuten, was natürlich fatal wäre. Würde man dann noch weiter machen verlängert sich die Sperrzeit nur noch. Deshalb fällt folgende Implementierung z.B in einem stark frequentierten Browsergame weg, wenn z.B eine Icq Nachricht gesendet werden kann, wenn man angegriffen wird:
PHP:
<?
$icq->login();
$icq->send_message("Hallo $user, deine Insel $koords steht unter Beschuss.");
$icq->logout();
?>
Wenn man nicht wegen der oft hintereinander folgenden Logins gekillt wird (was meistens schon nach 5 Stück passiert), dann, wenn man zuviele Nachrichten schickt. Dann werden Nachrichten, die man schickt einfach nicht mehr weitergeleitet.
Eine Lösung muss also her für dieses Problem. Das größte Problem ist bisher wie man es umgeht, dass man sich bei jedem Scriptaufruf neu einloggen muss. Wenn man eine Verbindung über fsockopen() aufbaut, dann wird diese automatisch nach Ende des Scriptaufrufs beendet und man müsste sich wieder neu einloggen. Eine mögliche Lösung ist die Funktion pfsockopen(). Sie hält die (Tcp) Verbindng auch nach Scriptausführung aufrecht (wenn man nicht fclose() macht). Das heißt, dass der Webserver auch nach Ablauf des Scriptes (also theorethisch 24/7) im Icq Online sein könnte und man so die Verbindung nur bei Bedarf neu aufbaut und man sich von da an nur noch um das Problem kümmern müsste wie man es veranlasst, dass nicht zu viele Nachrichten auf einmal geschickt werden (darauf komme ich später zurück).
Jedoch tuen sich bei einer permanenten Verbindung weitere Probleme auf. Wie stelle ich fest, dass schon eine Verbindung zum Icq Server besteht und ich direkt eine Nachricht senden kann ohne mich vorher einzuloggen? Also wie stelle ich fest, dass ich schon eingelogged bin. Auch habe ich manchmal das Problem, wenn die Verbindung nicht nach Scriptaufruf beendet (also permanent ist) wird (entweder durch pfsockopen() und kein fclose() oder das Script durch einen Error mittendrin abgebrochen wird (durch php) und er so nicht bis zum fclose() nicht kommt), dass dann noch irgendwelcher Müll im Stream-Buffer (ich nenn das mal so) befindet und sich dann, wenn man einen neuen Scriptaufruf macht der sich vor das neu Empfangene schiebt(natürlich steht es einfach nur davor weil es noch vom letzten Aufruf drinsteht) und so natürlich das Script zum Abruch bringt, weil diese Daten dann natürlich zu dem Zeitpunkt nicht erwartet werden und die Funktion abgebrochen wird. Vielleicht gibt es hier einen Spezialisten auf dem Gebiet, der mal was dazu sagen kann
Zu dem Problem, dass zu viele Nachrichten geschickt werden habe ich mir folgende Lösung überlegt:
Und zwar schickt der Server jedem Clienten (also auch meinem Script) beim einloggen ein Packet, welches für jeden Service Informationen enthält (Login, Nachrichten etc.) wie das sogenannte "Flow-Limit" festgelegt ist. Dieses wird im Moment noch nicht verwaltet, weil das fast 1KB Daten sind und das sehr sehr viel Arbeit wird das zu parsen und gescheit zu speichern. Da muss ich mich erstmal genauer mit beschäftigen.
Die Klasse könnte also bei jeder geschickten Nachricht das Flow-Limit überprüfen und, wenn noch neue Nachrichten geschickt werden können einfach die Nachricht abschicken ansonsten wird die Nachricht in eine Art Buffer geschrieben(Textdatei) und nichts passiert. Ein Cronjob könnte dann dafür sorgen, dass die Nachrichten abgeschickt werden. In dem befindet sich eine Schleife die, die Nachrichten im Buffer durchgeht und falls noch neue Nachrichten gesendet werden können die absendet (es muss halt nur dafür gesorgt werden, dass sie nicht zu schnell hintereinander geschickt werden). Für Seiten, die ein sehr großes Nachrichtenaufkommen haben könnte man dann mehre Accounts eintragen und der Cronjob wechselt dann den Account, wenn er zu viele Nachrichten geschickt hat (bevor der Account gemuted wird). Laufzeit des Scripts sollte man natürlich mit Zeitabstand zwischen den Aufrufen abstimmen, damit es einerseits fast immer läuft und andererseits nicht aufgerufen wird, wenn es bereits läuft.
Ihr seht ein ziemlich komplexes Thema. Wenn ihr Tipps habt oder euren Senf dazu abgeben wollt wie ihr es machen würdet dann bitte her damit, denn dafür habe ich dieses Posting erstellt. Ich hoffe es macht sich überhaupt jemand die Mühe und liest sich das durch.