Jak facebook, gmail wysyła powiadomienia w czasie rzeczywistym?

Przeczytałem kilka postów na ten temat i odpowiedzi to comet, reverse ajax, HTTP streaming, server push itp.

Jak działa powiadomienie poczty przychodzącej w Gmailu?

W Jaki Sposób Gmail Chat może wysyłać żądania AJAX bez interakcji z klientem?

Chciałbym wiedzieć, czy są jakieś odniesienia do kodu, które mogę wykonać, aby napisać bardzo prosty przykład. Wiele postów lub stron internetowych po prostu mówić o technologii. Trudno jest znaleźć pełną próbkę kod. Ponadto wydaje się, że można użyć wielu metod do implementacji komety, np. Hidden IFrame, XMLHttpRequest. Moim zdaniem korzystanie z XMLHttpRequest jest lepszym wyborem. Co sądzisz o zaletach i wadach różnych metod? Którego z nich używa Gmail?

Wiem, że musi to zrobić zarówno po stronie serwera, jak i po stronie klienta. Czy istnieje jakiś przykładowy kod PHP i Javascript?

 255
Author: Community, 2009-07-06

5 answers

Sposób, w jaki Facebook to robi, jest dość interesujący.

Powszechną metodą robienia takich powiadomień jest przepytywanie skryptu na serwerze (za pomocą AJAX) w danym przedziale czasowym (być może co kilka sekund), aby sprawdzić, czy coś się stało. Jednak może to być dość intensywne w sieci i często składasz bezsensowne prośby, ponieważ nic się nie stało.

[[2]] sposób, w jaki Facebook to robi, to wykorzystanie podejścia kometowego, zamiast sondażu w interwale, gdy tylko jedna ankieta się skończy, to wydaje kolejny. Jednak każde żądanie do skryptu na serwerze ma bardzo długi czas oczekiwania, a serwer odpowiada na żądanie tylko wtedy, gdy coś się stało. Możesz to zobaczyć, jeśli pojawisz się na karcie konsoli Firebug na Facebook, a żądania do skryptu mogą potrwać kilka minut. Jest to naprawdę bardzo pomysłowe, ponieważ ta metoda zmniejsza natychmiast zarówno liczbę zapytań, jak i częstotliwość ich wysyłania. Skutecznie masz teraz ramy eventowe pozwala to serwerowi na "odpalanie" zdarzeń.

Za tym, jeśli chodzi o faktyczną treść zwróconą z tych ankiet, jest to odpowiedź JSON, z czymś, co wydaje się być listą wydarzeń i informacjami o nich. Jest jednak minifikowany, więc jest trochę trudny do odczytania.

Jeśli chodzi o faktyczną technologię, AJAX jest tutaj drogą, ponieważ możesz kontrolować limity czasu żądania i wiele innych rzeczy. Polecam (Stack overflow cliche tutaj) korzystanie z jQuery zrobić AJAX, zajmie dużo problemy z kompatybilnością krzyżową. Jeśli chodzi o PHP, możesz po prostu przepytywać tabelę bazy danych dziennika zdarzeń w swoim skrypcie PHP i wracać do klienta tylko wtedy, gdy coś się stanie? Jest, jak sądzę, wiele sposobów realizacji tego.

Wykonanie:

Strona Serwera:

Wydaje się, że jest kilka implementacji bibliotek comet w PHP, ale szczerze mówiąc, to naprawdę jest bardzo proste, coś w rodzaju następującego pseudokodu:

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

echo json_encode(get_events());
  • Na funkcja has_event_happened po prostu sprawdzi, czy coś się stało w tabeli zdarzeń lub coś takiego, a następnie funkcja get_events zwróci listę nowych wierszy w tabeli? Zależy od kontekstu problemu naprawdę.

  • Nie zapomnij zmienić swojego maksymalnego czasu wykonania PHP, w przeciwnym razie nastąpi to wcześniej!

Strona Klienta:

Spójrz na wtyczkę jQuery do wykonywania interakcji:

To powiedziawszy, plugin wydaje się dodawać sporo złożoności, to naprawdę jest bardzo proste na kliencie, być może (z jQuery) coś w stylu:

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

Wszystko zależy w dużej mierze od tego, jak twoja istniejąca architektura jest połączona.

 405
Author: Kazar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-10 14:06:02

Update

Ponieważ nadal otrzymuję głosy na ten temat, myślę, że rozsądne jest pamiętać, że ta odpowiedź ma 4 lata. Sieć rozrosła się w bardzo szybkim tempie, więc proszę pamiętać o tej odpowiedzi.


Miałem ten sam problem Ostatnio i badałem na ten temat.

Podane rozwiązanie nazywa się long polling, a aby poprawnie z niego korzystać, musisz mieć pewność, że twoje żądanie AJAX ma "duży" limit czasu i zawsze wykonywać to żądanie po bieżącym zakończeniu (timeout, błąd lub sukces).

Long Ankiet-Klient

Tutaj, aby Kod był krótki, użyję 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);

}

Należy pamiętać, że (z jQuery docs):

W jQuery 1.4.x i poniżej, obiekt XMLHttpRequest będzie w stan nieprawidłowy, jeśli żądanie się kończy; dostęp do jakichkolwiek elementów obiektu może rzucić wyjątek. Tylko w Firefoksie 3.0+, skrypt i JSONP żądania nie mogą być anulowane przez limit czasu; skrypt uruchomi się nawet jeśli pojawia się po okresie czasu.

Long Ankiet-Serwer

Nie jest w żadnym konkretnym języku, ale byłoby to coś takiego:

function handleRequest () {  

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

     return events();

} 

Tutaj hasTimedOut upewni się, że Twój kod nie będzie czekał w nieskończoność, a anythingHappened sprawdzi, czy doszło do jakiegoś zdarzenia. {[4] } jest za zwolnienie wątku, aby robić inne rzeczy, podczas gdy nic się nie dzieje. events zwróci słownik zdarzeń (lub dowolną inną strukturę danych, którą wolisz) w formacie JSON (lub dowolnym innym woli).

To z pewnością rozwiązuje problem, ale jeśli martwisz się o skalowalność i wydajność, tak jak ja podczas badań, możesz rozważyć inne rozwiązanie, które znalazłem.

Rozwiązanie

Użyj gniazd!

Po stronie klienta, aby uniknąć problemów ze zgodnością, użyj socket.io . próbuje używać gniazda bezpośrednio i ma alternatywy dla innych rozwiązań, gdy gniazda nie są dostępne.

Po stronie serwera Utwórz serwer używając NodeJS (przykład tutaj ). Klient zasubskrybuje ten kanał (observer) utworzony wraz z serwerem. Za każdym razem, gdy powiadomienie ma zostać wysłane, jest ono publikowane na tym kanale, a subskrybent (Klient) zostaje powiadomiony.

Jeśli nie podoba ci się to rozwiązanie, spróbuj APE (Ajax Push Engine). Mam nadzieję, że pomogłem.
 37
Author: Walter Macambira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-20 00:24:25

Facebook Facebook wykorzystuje technologię comet do "wypychania" Wiadomości do przeglądarek internetowych. Serwer Comet Facebook jest zbudowany na otwartym serwerze Erlang Web Server mochiweb.

Na poniższym obrazku wyrażenie "klastry kanałów" oznacza "serwery komet".

Przegląd systemu

Wiele innych dużych stron internetowych buduje własny serwer comet, ponieważ istnieją różnice między potrzebami każdej firmy. Ale Zbuduj swój własny serwer comet na serwer Comet open source to dobre podejście.

Możesz wypróbować icomet , Serwer c1000k C++ comet zbudowany z libevent. icomet zapewnia również bibliotekę JavaScript, jest łatwy w użyciu tak proste, jak:

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 obsługuje szeroką gamę przeglądarek i systemów operacyjnych, w tym Safari( iOS, Mac), IEs(Windows), Firefox, Chrome itp.
 17
Author: ideawu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-18 15:55:21

Facebook używa MQTT zamiast HTTP. Popychanie jest lepsze niż sondażowanie. Poprzez HTTP musimy nieustannie sprawdzać serwer, ale poprzez serwer MQTT wypycha wiadomość do klientów.

Porównanie między MQTT i HTTP: http://www.youtube.com/watch?v=-KNPXPmx88E

Uwaga: moje odpowiedzi najlepiej pasują do urządzeń mobilnych.

 5
Author: abhinav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-01 16:45:25

Ważną kwestią przy długich sondażach jest obsługa błędów. Istnieją dwa rodzaje błędów:

  1. W takim przypadku Klient powinien natychmiast przywrócić połączenie. Jest to normalne wydarzenie w długich sondażach, gdy nie dotarły żadne wiadomości.

  2. Błąd sieci lub błąd wykonania. Jest to rzeczywisty błąd, który klient powinien z wdzięcznością zaakceptować i poczekać, aż serwer wróci on-line.

Główne problem polega na tym, że jeśli twój handler błędów natychmiast przywróci połączenie również dla błędu typu 2, klienci będą DOS serwera.

Obie odpowiedzi z próbką kodu tego nie rozumieją.

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
 5
Author: Ronenz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-12 20:33:29