2010-09-02 13 views
8

Pracuję na zwykłej aplikacji do czatu, prawdopodobnie od 10 do 20 użytkowników na pokój.Prosty skrypt czatowania z długim zapytaniem PHP, zbyt prosty?

Skrypt, który wysyła zapytanie do bazy danych o nowe wiadomości, jest zbyt prosty dla wszystkich żądań, które otrzyma.

Poniżej znajduje się fragment kodu, że pętle są nowe wiadomości, reszta skryptu jest po prostu coraz zmienne, budowa zapytania i obiekt odpowiedzi json:

$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; 
    } 
} 

Blok powyżej będzie kwerendy baza danych dla nowych wiadomości co sekundę przez 10 sekund, jeśli po 10 sekundach nie będzie nowych wiadomości, powiadomi przeglądarkę. Przeglądarka czeka 5 sekund, a następnie wysyła kolejne żądanie , aby uzyskać nowe wiadomości.

Jednak jeśli skrypt znajdzie nowe wiadomości, przeglądarka będzie żądać nowych wiadomości natychmiast po otrzymaniu odpowiedzi z nowymi wiadomościami z serwera.

Ten proces trwa i trwa ...

Więc w jaki sposób można zoptymalizować ten proces dalej? Czy to jest tak dobre, jak to tylko możliwe? Działa dobrze na moim lokalnym serwerze, ale obawiam się, że tylko kilku użytkowników może przeciążyć serwer na żywo (host udostępniony) ze wszystkimi żądaniami i zapętleniami.

Oto żywo DEMO można sprawdzić z Firebug http://pixbush.com/chat/chat.php

+3

Prostota jest tym, co my jako programiści ** dążymy do **. –

+4

Link nie działa. – kachar

Odpowiedz

2

Ten krzyczy dla AJAX.

Zobacz mój wpis dzisiaj na how to send JavaScript responses to PHP. Nie ma powodu, dla którego twój skrypt powinien w ogóle pętać.


EDYCJA: Moje złe o AJAX. Kiedy napisałem chatbota IRC PHP-Egg, natknąłem się na ten problem * 100. Sposób, w jaki go rozwiązałem (z powrotem w PHP 4 dni, pamiętajcie) był dla PHP pcntl_fork() i po prostu zwracaj za każdym razem, gdy pojawiała się wiadomość. Korzyścią jest to, że w 100% nie blokuje procesora, w przeciwieństwie do trybu uśpienia() i jest DUŻO szybszy niż 10 sekund lub dowolny arbitralny limit, który na niego nakładasz.


ja znowu rewizji moją odpowiedź (przepraszam!):

użyć jakiegoś procesu asynchronicznego że zrzuca tekst do pliku.

To co chcesz zrobić, to

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

Korzyści: Ograniczone użycie SQL; nie ma potrzeby pętli.

+3

Jestem prawie pewny, że OP * * używa AJAX razem z ** długim sondowaniem **, jak stwierdza to pytanie. http://en.wikipedia.org/wiki/Comet_(programming)#Ajax_with_long_polling – deceze

+0

@Pablo: Kilka tutoriali, które mogą ci pomóc: 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 -czat/. AJAX jest z pewnością drogą do zrobienia. –

+1

im przy użyciu AJAX, Plus im Looping na serwerze, aby zminimalizować żądania AJAX. – Pablo

0

Możesz spróbować użyć plików oznaczonych według conversationId zamiast DB i po prostu sprawdź, czy plik został "dotknięty". Użyj także usleep i set_time_limit (dla serwera Windows), aby ustawić interwał w milisekach i wydłużyć czas uśpienia. Usleep faktycznie, opóźnia użycie procesora, ale nadal jest pożarem natychmiast po tym, jak plik został zmieniony.

Oto sekcja mojego skryptu czatu. =)

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

Tak jak moja odpowiedź, więc się zgadzam. –

+0

i jak dokładnie upewniasz się, że plik nie zostanie uszkodzony przez równoczesny dostęp i być może zapisany w tym samym czasie? – Pablo

+0

W przypadku równoczesnego dostępu, FS blokuje pliki, nie uszkadzając ich. Jeśli tak się stanie, żadna zmiana nie zostanie wykonana. Może się zdarzyć 1 na 50 szans, że tak się stanie. Szansa jest zbyt niska, by sprawić, że będzie się pokazywał. Plus, ten sam problem występuje również, jeśli używasz DB. Pliki są lepsze, teoretycznie, ponieważ "zwalniają" zamek i reagują szybciej niż DB. – sheeks06

3

Z twojego opisu wynika, że ​​masz 5-sekundową przerwę milczenia, która pokonuje korzyść z długiego sondowania. Niech przeglądarka uruchomi kolejne żądanie natychmiast, gdy połączenie zostanie zwrócone (długie lub krótkie) z serwera. Podczas tworzenia kopii zapasowej, przy każdym wywołaniu serwera, przeglądarka powinna uruchamiać limit czasu nieco dłuższy niż limit czasu po stronie serwera, ale anulować go po zwróceniu żądania. Jeśli żądanie serwera kiedykolwiek się nie powiedzie i upłynie limit czasu przeglądarki, uruchom nowe żądanie.

1

Robiłem czat internetowy i natknąłem się na to samo rozwiązanie do utrzymywania aktualizacji w czasie rzeczywistym. Zastanawiam się więc, czy udało ci się to wymyślić: czy jest to dobry sposób na utrzymanie pętli po stronie serwera przy użyciu funkcji sleep(), czy może lepiej użyć więcej zapytań ajaxowych zamiast tego. Czy funkcja sleep() jest naprawdę dobrym pomysłem i nie zatrzyma serwera, gdy kilka sonduje sondowanie?

Widzę, że meebo używa długiego sondowania (czas między zapytaniami zależy również od ostrości okna), podczas gdy aplikacja SO czatuje. wydaje się po prostu używać tylko kwerendy ajax. Więc to mnie zastanawia.

+1

długie sondowanie za pomocą funkcji uśpienia() brzmi dobrze na papierze, a jeszcze lepiej podczas pracy na lokalnym komputerze testowym. Ale na serwerze na żywo (dzielonego hostingu) nie tak dużo, to kładzie zbyt duży nacisk na serwer. Ostatecznie zdecydowałem się zachować tylko prośby ajaxowe, bez długich sondaży. Stworzyłem również pewną logikę, aby zwiększyć i zmniejszyć stawkę żądań ajaxów w zależności od poziomu aktywności i sytuacji. – Pablo

+0

dziękuję za odpowiedź, zobaczę, jak minęła moja długa ankieta, a następnie zdecyduj, czy ją opuścić, czy odmówić – dr3w