¿Cómo envía Facebook y Gmail la notificación en tiempo real?

Resuelto Billy asked hace 15 años • 5 respuestas

He leído algunas publicaciones sobre este tema y las respuestas son cometa, ajax inverso, transmisión http, inserción de servidor, etc.

¿Cómo funciona la notificación de correo entrante en Gmail?

¿Cómo puede GMail Chat realizar solicitudes AJAX sin interacción con el cliente?

Me gustaría saber si hay referencias de código que pueda seguir para escribir un ejemplo muy simple. Muchas publicaciones o sitios web simplemente hablan de la tecnología. Es difícil encontrar un código de muestra completo. Además, parece que se pueden utilizar muchos métodos para implementar el cometa, por ejemplo, Hidden IFrame, XMLHttpRequest. En mi opinión, utilizar XMLHttpRequest es una mejor opción. ¿Qué opinas de los pros y los contras de los diferentes métodos? ¿Cuál usa Gmail?

Sé que debe hacerlo tanto en el lado del servidor como en el del cliente. ¿Existe algún código de muestra de PHP y Javascript?

Billy avatar Jul 06 '09 17:07 Billy
Aceptado

La forma en que Facebook hace esto es bastante interesante.

Un método común para realizar este tipo de notificaciones es sondear un script en el servidor (usando AJAX) en un intervalo determinado (tal vez cada pocos segundos), para comprobar si ha sucedido algo. Sin embargo, esto puede consumir bastante red y, a menudo, se realizan solicitudes inútiles porque no ha sucedido nada.

La forma en que Facebook lo hace es utilizando el enfoque del cometa, en lugar de realizar encuestas en un intervalo, tan pronto como se completa una encuesta, emite otra. Sin embargo, cada solicitud al script en el servidor tiene un tiempo de espera extremadamente largo y el servidor solo responde a la solicitud una vez que algo ha sucedido. Puedes ver que esto sucede si abres la pestaña Consola de Firebug mientras estás en Facebook, y las solicitudes de un script posiblemente tomen unos minutos. Realmente es bastante ingenioso, ya que este método reduce inmediatamente tanto el número de solicitudes como la frecuencia con la que hay que enviarlas. Ahora efectivamente tiene un marco de eventos que permite al servidor "disparar" eventos.

Detrás de esto, en términos del contenido real devuelto por esas encuestas, hay una respuesta JSON, con lo que parece ser una lista de eventos e información sobre ellos. Está minimizado, por lo que es un poco difícil de leer.

En términos de tecnología real, AJAX es el camino a seguir aquí, porque puede controlar los tiempos de espera de las solicitudes y muchas otras cosas. Recomendaría (cliché de desbordamiento de pila aquí) usar jQuery para hacer AJAX, eliminará muchos de los problemas de compatibilidad cruzada. En términos de PHP, ¿podría simplemente sondear una tabla de base de datos de registro de eventos en su script PHP y solo regresar al cliente cuando suceda algo? Supongo que hay muchas maneras de implementar esto.

Implementar:

Lado del servidor:

Parece haber algunas implementaciones de bibliotecas comet en PHP, pero para ser honesto, en realidad es muy simple, algo parecido quizás al siguiente pseudocódigo:

while(!has_event_happened()) {
   sleep(5);
}

echo json_encode(get_events());
  • ¿La función has_event_happened simplemente verificaría si algo había sucedido en una tabla de eventos o algo así, y luego la función get_events devolvería una lista de las nuevas filas en la tabla? Realmente depende del contexto del problema.

  • ¡No olvide cambiar el tiempo máximo de ejecución de PHP; de lo contrario, el tiempo de espera se agotará antes de tiempo!

Lado del cliente:

Eche un vistazo al complemento jQuery para realizar la interacción con Comet:

  • Página de inicio del proyecto: http://plugins.jquery.com/project/Comet
  • Código de Google: https://code.google.com/archive/p/jquerycomet/ : parece tener algún tipo de uso de ejemplo en el repositorio de Subversion.

Dicho esto, el complemento parece agregar un poco de complejidad, realmente es muy simple en el cliente, tal vez (con jQuery) algo como:

function doPoll() {
   $.get("events.php", {}, function(result) {
      $.each(result.events, function(event) { //iterate over the events
          //do something with your event
      });
      doPoll(); 
      //this effectively causes the poll to run again as
      //soon as the response comes back
   }, 'json'); 
}

$(document).ready(function() {
    $.ajaxSetup({
       timeout: 1000*60//set a global AJAX timeout of a minute
    });
    doPoll(); // do the first poll
});

Todo depende en gran medida de cómo se arme su arquitectura existente.

Alistair Evans avatar Jul 06 '2009 10:07 Alistair Evans

Actualizar

Mientras sigo recibiendo votos positivos sobre esto, creo que es razonable recordar que esta respuesta tiene 4 años. La Web ha crecido a un ritmo muy rápido, así que tenga en cuenta esta respuesta.


Tuve el mismo problema recientemente e investigué sobre el tema.

La solución proporcionada se llama sondeo largo y para usarla correctamente debe asegurarse de que su solicitud AJAX tenga un tiempo de espera "grande" y realizar siempre esta solicitud después de que finalice la corriente (tiempo de espera, error o éxito).

Encuesta larga: cliente

Aquí, para mantener el código breve, usaré jQuery:

function pollTask() { 

    $.ajax({

        url: '/api/Polling',
        async: true,            // by default, it's async, but...
        dataType: 'json',       // or the dataType you are working with
        timeout: 10000,          // IMPORTANT! this is a 10 seconds timeout
        cache: false

    }).done(function (eventList) {  

       // Handle your data here
       var data;
       for (var eventName in eventList) {

            data = eventList[eventName];
            dispatcher.handle(eventName, data); // handle the `eventName` with `data`

       }

    }).always(pollTask);

}

Es importante recordar que (de jQuery docs ):

En jQuery 1.4.x y versiones anteriores, el objeto XMLHttpRequest estará en un estado no válido si la solicitud expira; acceder a cualquier miembro del objeto puede generar una excepción. Solo en Firefox 3.0+, las solicitudes de secuencias de comandos y JSONP no se pueden cancelar mediante un tiempo de espera; el script se ejecutará incluso si llega después del período de tiempo de espera.

Sondeo largo: servidor

No está en ningún idioma concreto, pero sería algo como esto:

function handleRequest () {  

     while (!anythingHappened() || hasTimedOut()) { sleep(2); }

     return events();

} 

Aquí, hasTimedOutse asegurará de que su código no espere para siempre y anythingHappenedverificará si ocurrió algún evento. Esto sleepes para liberar tu hilo para hacer otras cosas mientras no pasa nada. Devolverá eventsun diccionario de eventos (o cualquier otra estructura de datos que prefiera) en formato JSON (o cualquier otro que prefiera).

Seguramente resuelve el problema, pero si está preocupado por la escalabilidad y el rendimiento como lo estaba yo cuando investigaba, podría considerar otra solución que encontré.

Solución

¡Usa enchufes!

En el lado del cliente, para evitar problemas de compatibilidad, utilice socket.io . Intenta utilizar socket directamente y tiene alternativas a otras soluciones cuando los sockets no están disponibles.

En el lado del servidor, cree un servidor usando NodeJS (ejemplo aquí ). El cliente se suscribirá a este canal (observador) creado con el servidor. Siempre que hay que enviar una notificación, se publica en este canal y se notifica al suscriptor (cliente).

Si no le gusta esta solución, pruebe APE ( Ajax Push Engine ).

Espero haber ayudado.

Walter Macambira avatar Apr 25 '2013 00:04 Walter Macambira

Según una presentación de diapositivas sobre el sistema de mensajería de Facebook , Facebook utiliza la tecnología cometa para "enviar" mensajes a los navegadores web. El servidor cometa de Facebook está construido sobre el servidor web de código abierto Erlang, mochiweb.

En la imagen siguiente, la frase "clústeres de canales" significa "servidores de cometas".

Resumen del sistema

Muchos otros grandes sitios web construyen su propio servidor comet, porque existen diferencias entre las necesidades de cada empresa. Pero construir su propio servidor cometa en un servidor cometa de código abierto es un buen enfoque.

Puedes probar icomet , un servidor cometa C1000K C++ creado con libevent. icomet también proporciona una biblioteca de JavaScript, es fácil de usar, tan simple como:

var comet = new iComet({
    sign_url: 'http://' + app_host + '/sign?obj=' + obj,
    sub_url: 'http://' + icomet_host + '/sub',
    callback: function(msg){
        // on server push
        alert(msg.content);
    }
});

icomet admite una amplia gama de navegadores y sistemas operativos, incluidos Safari (iOS, Mac), IE (Windows), Firefox, Chrome, etc.

ideawu avatar Oct 01 '2013 02:10 ideawu