2010-09-02 14 views
8

Im trabajando en una aplicación de chat simple, probablemente de 10 a 20 usuarios por habitación.Escritura simple de chat de larga duración de PHP, ¿es demasiado simple?

El script que consulta la base de datos en busca de nuevos mensajes parece demasiado simple para todas las solicitudes que recibirá.

A continuación se muestra el bloque de código que se repite para los mensajes nuevos, el resto del guión es sólo conseguir las variables, la construcción de la consulta y el objeto respuesta 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; 
    } 
} 

El bloque de instrucción anterior al base de datos para mensajes nuevos cada segundo durante 10 segundos, si después de los 10 segundos no hay mensajes nuevos notificará al navegador. El navegador espera 5 segundos y luego envía otra solicitud al para recibir mensajes nuevos.

Sin embargo, si la secuencia de comandos encuentra nuevos mensajes, el navegador solicitará más mensajes nuevos al instante tan pronto como reciba la respuesta con los nuevos mensajes del servidor.

Este proceso sigue y sigue ...

Entonces, ¿cómo puedo optimizar este proceso más lejos? ¿Es esto tan bueno como se pone? Funciona bien en mi servidor local, pero me temo que solo unos pocos usuarios podrían sobrecargar un servidor en vivo (host compartido) con todas las solicitudes y los bucles.

Aquí es demostración en vivo se puede comprobar con Firebug http://pixbush.com/chat/chat.php

+3

Simplicity es lo que nosotros como programadores ** nos esforzamos **. –

+4

El enlace ya no funciona. – kachar

Respuesta

2

Este grita para AJAX.

Ver mi publicación hoy en how to send JavaScript responses to PHP. No hay ninguna razón por la que tu script deba tener un loop en absoluto.


EDIT: My bad about the AJAX. Cuando escribí IRC chatbot PHP-Egg, me topé con este problema * 100. La forma en que lo resolví (de vuelta en PHP 4 días, fíjate) fue a pcntl_fork() PHP y simplemente lo devuelvo cada vez que había un mensaje. Los beneficios son que no bloquea al 100% la CPU, a diferencia de sleep() y es MUCHO más rápido que 10 segundos o cualquier límite arbitrario que le pongas.


estoy revisando mi respuesta de nuevo (lo siento!):

uso de algún tipo de proceso asíncrono que vuelca el texto en un archivo.

Entonces lo que se hace es

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

Beneficios: uso limitado de SQL; no es necesario buclear

+3

Estoy bastante seguro de que OP * está * usando AJAX junto con ** larga-encuesta **, como dice la pregunta. http://en.wikipedia.org/wiki/Comet_(programming)#Ajax_with_long_polling – deceze

+0

@Pablo: algunos tutoriales que pueden ayudarte aquí: 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 -charla/. AJAX es sin duda el camino a seguir. –

+1

im utilizando AJAX, Plus im Looping en el servidor para minimizar las solicitudes de AJAX. – Pablo

0

Puede intentar usar archivos etiquetados de acuerdo con conversationId en lugar de un DB y simplemente verificar si el archivo ha sido 'tocado'. Además, use usleep y set_time_limit (para Windows Server) para establecer su intervalo en milisegundos y aumentar el tiempo de suspensión. En realidad, Usleep duerme, retrasa el uso de la CPU pero todavía se dispara al instante en caso de que el archivo haya sido cambiado.

Aquí hay una sección de mi script de chat. =)

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

Igual que mi respuesta, así que estoy de acuerdo. –

+0

y cómo exactamente se asegura de que el archivo no se corrompa por el acceso simultáneo y posiblemente se haya escrito al mismo tiempo? – Pablo

+0

Para el acceso simultáneo, FS bloquea los archivos que no lo corrompen. Si esto sucede, no se realizará ningún cambio. Hay tal vez 1 de 50 posibilidades de que esto suceda. La posibilidad es demasiado baja para que sea un impedimento para el espectáculo. Además, el mismo problema también ocurre si usa un DB. Los archivos son mejores, en teoría, porque "liberan" el bloqueo y responden más rápido que los DB. – sheeks06

3

Desde su descripción, parece que usted tiene un segundo trozo de silencio 5, que vence el beneficio de largo votación. Haga que el navegador inicie otra solicitud inmediatamente cuando se devuelva una llamada (larga o corta) desde el servidor. Como una copia de seguridad, con cada llamada al servidor, haga que el navegador inicie un tiempo de espera ligeramente más largo que el tiempo de espera del servidor, pero cancélelo cuando se devuelva una solicitud. Si la solicitud del servidor falla alguna vez y el tiempo de espera del navegador se completa, inicie una nueva solicitud.

1

He estado haciendo chateo web y me encontré con la misma solución para mantener las actualizaciones en tiempo real. Entonces, me pregunto si ya lo has entendido: ¿es una buena manera de seguir girando por el lado del servidor usando la función sleep(), o tal vez es mejor usar más consultas ajax en su lugar? ¿Y la función sleep() realmente es una buena idea y no detendrá el servidor cuando varios usuarios están sondeando?

Veo a meebo usando una encuesta larga (el tiempo entre consultas también depende del enfoque de la ventana, supongo) mientras SO chat app. parece que solo está usando consultas ajax. Entonces eso me hace preguntarme.

+1

largo sondeo con la función sleep() suena bien en papel y aún mejor cuando se ejecuta en la máquina de prueba local. Pero en el servidor en vivo (hosting compartido) no tanto, pone demasiado estrés en el servidor. Finalmente decidí mantener solo las solicitudes de ajax, no largas encuestas. También creé algo de lógica para aumentar y disminuir la tasa de solicitudes de Ajax dependiendo del nivel de actividad y situación. – Pablo

+0

gracias por la respuesta, voy a ver cómo va mi larga votación y luego decidir si dejarla o rechazarla – dr3w