2010-09-02 8 views
8

Ich arbeite an einer einfachen Chat-App, wahrscheinlich 10 bis 20 Benutzer pro Zimmer.Einfache PHP lange Polling-Chat-Skript, zu einfach?

Das Skript, das die Datenbank nach neuen Nachrichten abfragt, sieht für alle Anfragen zu einfach aus.

Unten ist der Codeblock, der für neue Nachrichten-Schleife wird der Rest des Skripts nur die Variablen bekommen, den Bau der Abfrage und das json Antwortobjekt:

$sleepTime = 1; //Seconds 
$data = ""; 
$timeout = 0; 

//Query database for data 
while(!$data and $timeout < 10){ 
    $data = getQuery($sql); 
    if(!$data){ 
     //No new messages on the chat 
     flush(); 
     //Wait for new Messages 
     sleep($sleepTime);   
     $timeout += 1; 
    }else{ 
     break; 
    } 
} 

Der Block oben wird Abfrage der Datenbank für neue Nachrichten jede Sekunde für 10 Sekunden, wenn nach den 10 Sekunden keine neuen Nachrichten sind, wird es den Browser benachrichtigen. Der Browser wartet 5 Sekunden und sendet dann eine weitere Anfrage , um neue Nachrichten zu erhalten.

Wenn das Skript jedoch neue Nachrichten findet, fordert der Browser sofort weitere neue Nachrichten an, sobald er die Antwort mit den neuen Nachrichten vom Server erhält.

Dieser Prozess geht weiter und weiter ...

So wie kann ich diesen Prozess weiter zu optimieren, welche? Ist das so gut wie es geht? Funktioniert gut auf meinem lokalen Server, aber ich habe Angst, dass nur ein paar Benutzer einen Live-Server (Shared Host) mit allen Anfragen und den Schleifen überlasten könnten.

Hier Live-Demo Sie http://pixbush.com/chat/chat.php mit Firebug überprüfen

+3

Einfachheit ist, was wir als Programmierer ** anstreben **. –

+4

Link funktioniert nicht mehr. – kachar

Antwort

2

Diese schreit für AJAX.

Siehe meinen Beitrag heute auf how to send JavaScript responses to PHP. Es gibt keinen Grund, warum Ihr Skript überhaupt eine Schleife ausführen sollte.


EDIT: Mein schlechtes über die AJAX. Als ich den IRC-Chatbot PHP-Egg schrieb, stieß ich auf dieses Problem * 100. Die Art, wie ich es löste (zurück in den PHP 4 Tagen, wohlgemerkt) war pcntl_fork() PHP und hat es einfach jedes Mal zurück, wenn es eine Nachricht gab. Die Vorteile sind, dass es die CPU im Gegensatz zu sleep() nicht zu 100% blockiert und VIEL schneller ist als 10 Sekunden oder irgendein beliebiges Limit, das Sie ihm zuweisen.


ich wieder meine Antwort revidieren (sorry!):

Verwenden eine Art asynchroner Prozess, der den Text in eine Datei Dumps.

Dann, was Sie tun würde, ist

if (filemtime ('chat.log')> time() - 5) { Echo json_encode (file_get_contents ('chat.log')); }

Vorteile: Begrenzte SQL-Verwendung; keine Schleife nötig.

+3

Ich bin ziemlich sicher, dass das OP * AJAX zusammen mit ** lang-polling ** verwendet, wie die Frage besagt. http://en.wikipedia.org/wiki/Comet_(programming)#Ajax_with_long_polling – deceze

+0

@Pablo: Ein paar Tutorials, die Ihnen hier helfen können: http://css-tricks.com/chat2/, http: // net. tutsplus.com/tutorials/javascript-ajax/how-to-create-a-simple-web-based-chat-application/, http://anantgarg.com/2009/05/13/gmail-facebook-style-jquery -Plaudern/. AJAX ist sicherlich der Weg zu gehen. –

+1

ich benutze AJAX, Plus im Looping auf dem Server, um die AJAX-Anfragen zu minimieren. – Pablo

0

Sie könnten versuchen, Dateien zu verwenden, die nach conversationId statt einer DB benannt sind, und nur prüfen, ob die Datei "berührt" wurde. Verwenden Sie außerdem usleep und set_time_limit (für Windows Server), um Ihr Intervall in Millisekunden festzulegen und die Ruhezeit zu erhöhen. Usleep verzögert zwar die CPU-Auslastung, wird jedoch sofort ausgelöst, wenn die Datei geändert wurde.

Hier ist ein Abschnitt meines Chat-Skripts. =)

define('SUCCESS', '__SUCCESS__'); 
define('FAILED', '__FAILED__'); 

$tmpLib = $TMPFOLDER; 
$msgPath = $MSGFILE; 

$timeout = $POLLSPEEDSEC; 

$acct = new Account($tmpLib, $_GET['key']); 

if (false === $acct) { 
    return false; 
} 

$msg = new Message($msgPath, $acct); 

$lastMod = !empty($_GET['ts']) ? $_GET['ts']: 0; 
$lastMod = substr($lastMod, 0, 10); 
$lastMod = (int)$lastMod; 

$result = array(); 

$start = gettimeofday(); 
$prevMsg = $acct->getTemp('cache'); 

do{ 
    usleep(10000); 

    if ($acct->getFileTime() >= $lastMod) { 
     $result['account'] = $acct->getAllOnline(); 
    } 

    if($msg->getFileTime() >= $lastMod) { 
     $result['message'] = $msg->fetch(); 
    } 

    if (!empty($result)) { 
     $theMsg = json_encode($result); 
     if ($theMsg != $prevMsg) { 
      $acct->setTemp('cache', $theMsg); 
      echo $theMsg; 
      flush(); 
      exit; 
     } 
     $result = array(); 
     $lastMod = time(); 
    } 

    $end = gettimeofday(); 
} while($timeout > ($end['sec'] - $start['sec'])); 

echo FAILED; 
+0

Das gleiche wie meine Antwort, also stimme ich zu. –

+0

und wie genau stellen Sie sicher, dass die Datei nicht korrumpiert wird, wenn Sie gleichzeitig Zugriff haben und möglicherweise gleichzeitig geschrieben wurden? – Pablo

+0

Für den gleichzeitigen Zugriff sperrt FS die Dateien nicht. Wenn dies geschieht, wird keine Änderung vorgenommen. Es gibt vielleicht 1 von 50 Chancen, dass dies passieren wird. Die Chance ist zu gering, um es zu einem Show-Stopper zu machen. Das gleiche Problem tritt auch auf, wenn Sie eine DB verwenden. Dateien sind in der Theorie besser, weil es die Sperre "freigibt" und schneller reagiert als DBs. – sheeks06

3

Aus Ihrer Beschreibung, es klingt wie Sie eine 5 Sekunden Lücke der Stille haben, die den Vorteil des lang Polling besiegt. Lassen Sie den Browser sofort eine weitere Anfrage starten, wenn ein Anruf (lang oder kurz) vom Server zurückkehrt. Zur Sicherung muss der Browser bei jedem Serveraufruf eine Zeitüberschreitung auslösen, die etwas länger ist als die Zeitlimitüberschreitung auf der Serverseite, aber abgebrochen werden, wenn eine Anforderung zurückgegeben wird. Wenn die Serveranforderung immer fehlschlägt und die Zeitüberschreitung des Browsers abgeschlossen ist, starten Sie eine neue Anforderung.

1

Ich habe Web-Chat gemacht und bin auf die gleiche Lösung gestoßen, um Echtzeit-Updates zu erhalten. Also, ich frage mich, ob Sie es herausgefunden haben: ist es eine gute Möglichkeit, serverseitig mit der Funktion sleep() zu loopen, oder vielleicht ist es besser, stattdessen mehr Ajax-Abfragen zu verwenden. Und ist die Funktion sleep() wirklich eine gute Idee und wird der Server nicht angehalten, wenn mehrere usres polling sind?

Ich sehe Meebo mit Long-Polling (Zeit zwischen Abfragen hängt auch von Fenster Fokus ich denke), während SO Chat App. scheint nur mit Ajax-Abfragen zu arbeiten. Das macht mich wundern.

+1

lange polling mit der sleep() funktion klingt gut auf dem papier und noch besser beim laufen auf lokalen testmaschine. Aber auf dem Live-Server (Shared Hosting) ist nicht so viel, es belastet den Server zu sehr. Ich habe mich letztendlich entschieden, nur die Ajax-Anfragen zu behalten, keine langen Umfragen. Ich habe auch eine Logik erstellt, um die Rate der Ajax-Anfragen je nach Aktivität und Situation zu erhöhen und zu verringern. – Pablo

+0

danke für die Antwort, ich werde sehen, wie meine lang-polling geht und dann entscheiden, ob Sie es verlassen oder ablehnen – dr3w