Lightweight Chat (AJAX, PHP/SQL, LONG POLLING)

Hallo zusammen,

im folgenden geht es um die Entwicklung eines PHP, AJAX Lightweight chat.

Problem

ich wollte seit langem meinen kleinen Chat aktualisieren. Bisher funktionierte der Chat wiefolgt: Alle 1,2 Sekunden hat der Client einen Request an den Server gestellt. Der Server hat immer die letzten 10 Chateinträge an den Client zurückgeschickt, alle 1,2 Sekunden jeweils für jeden Client. Das führt bei vielen Clients und einem ruhigen Chat zu genau soviel Datenverkehr wie bei einem belebten Chat. Sehr ungünstig also!

Websocket und HTML5

Theoretisch ist es möglich mit Websockets eine TCP Verbindung zwischen Server und Client aufzubauen. Dann wird ohne Header jeweils nur das versendet was auch versendet werden soll. Dazu kann der Server einen Pull-Request absetzen und wir erhalten einen optimalen Chat. Dummerweise kann der Firefox 11 dies nicht, da er sich noch nicht an den Standard hält. Nur Googles Chrome war bei mir in der Lage dies umzusetzen, daher ist diese optimale Lösung bisher nicht verfügbar

long polling

Mein Chat basiert daher auf Long Polling. Der Client setzt einen Request an den Server. Der Server beantwortet nun erst dann den Request, wenn es auch etwas neues für den Client gibt. Das führt zu erheblich veringertem Datenverkehr!

Es bleibt zu klären wie der Server wissen kann, was für den Client neu ist und was nicht, doch dazu später mehr.

php/mysql Struktur des Chats

Der Chat ist simple gehalten und hat folgende SQL Struktur

CREATE TABLE IF NOT EXISTS `chat` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`zeit` datetime NOT NULL,
`uid` varchar(250) NOT NULL,
`nachricht` text NOT NULL,
`ip` varchar(80) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Die Felder sollten selbsterklärend sein.

Die spannende Frage ist, wie entscheidet der Server was neu ist und was nicht. Dazu folgende Idee: Der Client schickt einen messageCounter als GET Variable zum Server. Diese beinhaltet die Nummer der letzten Nachricht (Anzahl der Gesamtnachrichten), diese ist am Anfang 0, da der Client nichts weiss! Der Server wiederum empfängt diese Zahl vom Client und kennt selber die aktuelle Zahl an Gesamtnachrichten. Diese vergleicht er jetzt dauernd mit der Zahl vom Client (nur serverseitig). Sollten zu einem Zeitpunkt mehr Nachrichten beim Server sein als die Variable messageCounter vom Client anzeigt, so muss der Client informiert werden. Der Server antwortet dem Client und sendet nun auch die neue Anzahl der Gesamtnachrichten. Der Client stellt automatisch wieder eine Frage mit den neuen messageCounter und das Spiel geht von vorn los.

server code

Wie wir hier sehen werden die 10 Einträge, die der Server dann schickt codiert in folgender Art:

# Trennung der Daten eines Eintrages mit Steuerzeichen 3
Eintrag = Timestamp \3 Username \3 Nachricht

# Trennung der Einträge mit Steuerzeichen 2
Nachricht = newMessageCount \2 Eintrag \2 Eintrag \2 ... \2

Das decodieren übernimmt dann das Javascript auf Clientseite

client code

Wie man hier sieht wird eine tabelle aufgebaut und zwar umgekehrt, weil wir die SQL Datenbank mit order by .. desc abgefragt hatten. Was hier nicht erwähnt ist, wie man Daten zum Server bekommt, aber das kann man nun in Handelsüblichen AJAX im Hintergrund erledigen, denn die Daten müssen jetzt nur noch in die SQL Datenbank.