Как Facebook, Gmail отправляют уведомления в режиме реального времени?

Я прочитал несколько постов на эту тему, и ответы на них - комета, обратный ajax, потоковое вещание http, загрузка сервера и т. Д.

Как работает уведомление о входящей почте в Gmail?

Как GMail Chat может делать запросы AJAX без взаимодействия с клиентом?

Я хотел бы знать, есть ли какие-либо ссылки на код, которым я могу следовать, чтобы написать очень простой пример. Многие посты или сайты просто говорят о технологиях. Трудно найти полный пример кода. Кроме того, кажется, что для реализации кометы можно использовать много методов, например Hidden IFrame, XMLHttpRequest. На мой взгляд, использование XMLHttpRequest - лучший выбор. Что вы думаете о плюсах и минусах разных методов? Какой из них использует Gmail?

Я знаю, что это нужно делать как на стороне сервера, так и на стороне клиента. Есть ли пример кода PHP и Javascript?

5 ответов

Решение

То, как Facebook делает это, довольно интересно.

Распространенным способом выполнения таких уведомлений является опрос сценария на сервере (с использованием AJAX) в течение заданного интервала (возможно, каждые несколько секунд), чтобы проверить, произошло ли что-то. Однако это может быть довольно интенсивно в сети, и вы часто делаете бессмысленные запросы, потому что ничего не произошло.

То, как Facebook делает это, использует кометный подход, а не опрашивает интервал, как только один опрос завершается, он выдает другой. Однако каждый запрос к сценарию на сервере имеет чрезвычайно длительный тайм-аут, и сервер отвечает на запрос только после того, как что-то произошло. Это может произойти, если вы откроете вкладку "Консоль" Firebug на Facebook, где запросы к сценарию могут занимать минуты. Это действительно гениально, так как этот метод сразу сокращает количество запросов и частоту их отправки. Теперь у вас есть структура событий, которая позволяет серверу "запускать" события.

Кроме того, с точки зрения фактического содержимого, возвращаемого этими опросами, это ответ в формате JSON, представляющий собой список событий и информацию о них. Он минимизирован, поэтому его немного сложно прочитать.

С точки зрения современной технологии, AJAX - это путь, потому что вы можете контролировать тайм-ауты запросов и многое другое. Я бы порекомендовал (клик по переполнению стека здесь) использовать jQuery для создания AJAX, это устранит многие проблемы кросс-совместимости. С точки зрения PHP, вы можете просто опрашивать таблицу базы данных журнала событий в своем PHP-сценарии и возвращаться к клиенту только тогда, когда что-то происходит? Я ожидаю, что есть много способов реализовать это.

Реализация:

Сторона сервера:

Кажется, в PHP есть несколько реализаций кометных библиотек, но, честно говоря, это действительно очень просто, что-то вроде следующего псевдокода:

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

echo json_encode(get_events());
  • Функция has_event_happened будет просто проверять, произошло ли что-нибудь в таблице событий или что-то в этом роде, а затем функция get_events выдаст список новых строк в таблице? Зависит от контекста проблемы действительно.

  • Не забудьте изменить максимальное время выполнения PHP, иначе время ожидания истечет!

Сторона клиента:

Взгляните на плагин jQuery для взаимодействия с Comet:

Тем не менее, плагин, кажется, добавляет немного сложности, он действительно очень прост для клиента, возможно (с jQuery) что-то вроде:

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

Все зависит во многом от того, как ваша существующая архитектура собрана воедино.

Обновить

Поскольку я продолжаю получать отклики по этому поводу, я думаю, что разумно помнить, что этому ответу 4 года. Веб развивался очень быстрыми темпами, поэтому, пожалуйста, помните об этом ответе.


У меня недавно была та же самая проблема и исследовал предмет.

Данное решение называется длинным опросом, и для правильного его использования вы должны быть уверены, что ваш AJAX-запрос имеет "большой" тайм-аут и всегда выполнять этот запрос после окончания текущего (тайм-аут, ошибка или успех).

Длинный опрос - Клиент

Здесь, для краткости кода, я буду использовать 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);

}

Важно помнить, что (из документов jQuery):

В jQuery 1.4.x и ниже объект XMLHttpRequest будет в недопустимом состоянии, если время ожидания истекло; доступ к любым членам объекта может вызвать исключение. Только в Firefox 3.0+ запросы на скрипты и JSONP не могут быть отменены тайм-аутом; скрипт будет работать, даже если он прибудет после истечения времени ожидания.

Длинный опрос - сервер

Это не на каком-то конкретном языке, но это будет примерно так:

function handleRequest () {  

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

     return events();

} 

Вот, hasTimedOut убедитесь, что ваш код не ждет вечно, и anythingHappened, проверит, произошло ли какое-либо событие. sleep для освобождения вашей темы, чтобы делать другие вещи, пока ничего не происходит. events возвратит словарь событий (или любую другую структуру данных, которую вы предпочитаете) в формате JSON (или любую другую, которую вы предпочитаете).

Это, безусловно, решает проблему, но, если вы обеспокоены масштабируемостью и производительностью, как я это делал при исследовании, вы могли бы рассмотреть другое решение, которое я нашел.

Решение

Используйте розетки!

На стороне клиента, чтобы избежать проблем совместимости, используйте https://socket.io/. Он пытается использовать сокет напрямую и использовать альтернативные решения, когда сокеты недоступны.

На стороне сервера создайте сервер, используя NodeJS (пример здесь). Клиент подпишется на этот канал (наблюдатель), созданный на сервере. Всякий раз, когда необходимо отправить уведомление, оно публикуется на этом канале, и подписчик (клиент) получает уведомление.

Если вам не нравится это решение, попробуйте APE ( Ajax Push Engine).

Надеюсь, я помог.

Согласно слайд-шоу о системе обмена сообщениями Facebook, Facebook использует технологию комет для " передачи " сообщений в веб-браузеры. Кометный сервер Facebook построен на открытом веб-сервере Erlang с открытым исходным кодом mochiweb.

На рисунке ниже фраза "кластеры каналов" означает "серверы комет".

Системный Обзор

Многие другие крупные веб-сайты создают свой собственный комет-сервер, потому что между потребностями каждой компании есть различия. Но построить свой собственный комет-сервер на комет-сервере с открытым исходным кодом - это хороший подход.

Вы можете попробовать icomet, кометный сервер C1000K C++, созданный с libevent. icomet также предоставляет библиотеку JavaScript, ее легко использовать так же просто, как:

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 поддерживает широкий спектр браузеров и операционных систем, включая Safari (iOS, Mac), IE (Windows), Firefox, Chrome и т. д.

Одна важная проблема с длинным опросом - обработка ошибок. Есть два типа ошибок:

  1. Время ожидания запроса может истечь, и в этом случае клиент должен немедленно восстановить соединение. Это нормальное событие при длительном опросе, когда сообщения не поступили.

  2. Ошибка сети или ошибка выполнения. Это фактическая ошибка, которую клиент должен изящно принять и дождаться, пока сервер вернется в оперативный режим.

Основная проблема заключается в том, что если ваш обработчик ошибок немедленно восстанавливает соединение и для ошибки типа 2, клиенты будут DOS сервером.

Оба ответа с примером кода пропускают это.

function longPoll() { 
        var shouldDelay = false;

        $.ajax({
            url: 'poll.php',
            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 (data, textStatus, jqXHR) {
             // do something with data...

        }).fail(function (jqXHR, textStatus, errorThrown ) {
            shouldDelay = textStatus !== "timeout";

        }).always(function() {
            // in case of network error. throttle otherwise we DOS ourselves. If it was a timeout, its normal operation. go again.
            var delay = shouldDelay ? 10000: 0;
            window.setTimeout(longPoll, delay);
        });
}
longPoll(); //fire first handler

Facebook использует MQTT вместо HTTP. Толчок лучше, чем опрос. Через HTTP нам нужно постоянно опрашивать сервер, но через MQTT-сервер отправляет сообщение клиентам.

Сравнение между MQTT и HTTP: http://www.youtube.com/watch?v=-KNPXPmx88E

Примечание: мои ответы лучше всего подходят для мобильных устройств.

Другие вопросы по тегам