To prostsze niż początkowo myślałem. Zasadniczo masz stronę, która nic nie robi, dopóki dane, które chcesz wysłać, nie będą dostępne (powiedzmy, że przybywa nowa wiadomość).
Oto naprawdę prosty przykład, który wysyła prosty ciąg znaków po 2-10 sekundach. 1 na 3 szanse na zwrócenie błędu 404 (aby pokazać obsługę błędów w nadchodzącym przykładzie Javascript)
msgsrv.php
<?php
if(rand(1,3) == 1){
/* Fake an error */
header("HTTP/1.0 404 Not Found");
die();
}
/* Send a string after a random number of seconds (2-10) */
sleep(rand(2,10));
echo("Hi! Have a random number: " . rand(1,10));
?>
Uwaga: w prawdziwej witrynie uruchomienie tego na zwykłym serwerze internetowym, takim jak Apache, spowoduje szybkie powiązanie wszystkich „wątków roboczych” i nie będzie w stanie odpowiedzieć na inne żądania. Można to zrobić na wiele sposobów, ale zaleca się napisanie „serwer długiego odpytywania” w czymś w rodzaju skręconego Pythona , który nie polega na jednym wątku na żądanie. cometD jest popularny (dostępny w kilku językach), a Tornado to nowa platforma stworzona specjalnie do takich zadań (została zbudowana dla długiego odpytywania FriendFeed) ... ale jako prosty przykład Apache jest więcej niż wystarczający ! Skrypt ten można łatwo napisać w dowolnym języku (wybrałem Apache / PHP, ponieważ są one bardzo popularne i zdarzyło mi się uruchamiać je lokalnie)
Następnie w Javascripcie żądasz powyższego pliku ( msg_srv.php
) i czekasz na odpowiedź. Kiedy je otrzymasz, działasz na podstawie danych. Następnie żądasz pliku i czekasz ponownie, działasz na podstawie danych (i powtórz)
Poniżej znajduje się przykład takiej strony. Gdy strona zostanie załadowana, wysyła początkowe żądanie msgsrv.php
pliku. Jeśli się powiedzie, dołączamy wiadomość do #messages
div, a następnie po 1 sekundzie ponownie wywołujemy funkcję waitForMsg, co powoduje oczekiwanie.
1 sekunda setTimeout()
jest naprawdę podstawowym ogranicznikiem szybkości, bez niej działa dobrze, ale jeśli msgsrv.php
zawsze wraca natychmiast (na przykład z błędem składni) - zalewasz przeglądarkę i może się szybko zawiesić. Lepiej byłoby to zrobić sprawdzając, czy plik zawiera prawidłową odpowiedź JSON i / lub utrzymując bieżącą liczbę żądań na minutę / sekundę i odpowiednio zatrzymując.
Jeśli strona popełni błąd, dołącza błąd do #messages
div, czeka 15 sekund, a następnie próbuje ponownie (identycznie, jak czekamy 1 sekundę po każdej wiadomości)
Zaletą tego podejścia jest to, że jest bardzo odporny. Jeśli połączenie internetowe klienta zostanie przerwane, nastąpi przekroczenie limitu czasu, a następnie spróbuj ponownie nawiązać połączenie - jest to nieodłączne od czasu działania odpytywania, nie jest wymagana skomplikowana obsługa błędów
W każdym razie long_poller.htm
kod, używając frameworka jQuery:
<html>
<head>
<title>BargePoller</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css" media="screen">
body{ background:#000;color:#fff;font-size:.9em; }
.msg{ background:#aaa;padding:.2em; border-bottom:1px #000 solid}
.old{ background-color:#246499;}
.new{ background-color:#3B9957;}
.error{ background-color:#992E36;}
</style>
<script type="text/javascript" charset="utf-8">
function addmsg(type, msg){
/* Simple helper to add a div.
type is the name of a CSS class (old/new/error).
msg is the contents of the div */
$("#messages").append(
"<div class='msg "+ type +"'>"+ msg +"</div>"
);
}
function waitForMsg(){
/* This requests the url "msgsrv.php"
When it complete (or errors)*/
$.ajax({
type: "GET",
url: "msgsrv.php",
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
success: function(data){ /* called when request to barge.php completes */
addmsg("new", data); /* Add response to a .msg div (with the "new" class)*/
setTimeout(
waitForMsg, /* Request next message */
1000 /* ..after 1 seconds */
);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
addmsg("error", textStatus + " (" + errorThrown + ")");
setTimeout(
waitForMsg, /* Try again after.. */
15000); /* milliseconds (15seconds) */
}
});
};
$(document).ready(function(){
waitForMsg(); /* Start the inital request */
});
</script>
</head>
<body>
<div id="messages">
<div class="msg old">
BargePoll message requester!
</div>
</div>
</body>
</html>
sleep(rand(2,10));
? aby nic nie robić, sonduj bazę danych co 100 milisekund? kiedy decyduje się umrzeć?Mam naprawdę prosty przykład czatu jako część slosh .
Edycja : (ponieważ wszyscy wklejają tutaj swój kod)
Jest to kompletny czat dla wielu użytkowników oparty na JSON, wykorzystujący długie odpytywanie i slosh . To jest demonstracja wykonywania połączeń, więc zignoruj problemy XSS. Nikt nie powinien tego wdrażać bez uprzedniej dezynfekcji.
Zauważ, że klient zawsze ma połączenie z serwerem i gdy tylko ktoś wyśle wiadomość, wszyscy powinni ją zobaczyć z grubsza natychmiast.
źródło
getNewComments
tam wywołaniem zwrotnym, więc po prostu odpala go na końcu każdego żądania ajaxTornado jest przeznaczony do długiego odpytywania i zawiera bardzo minimalną (kilkaset linii Pythona) aplikację do czatowania w / Examples / chatdemo , w tym kod serwera i kod klienta JS. Działa to tak:
Klienci używają JS do żądania aktualizacji, ponieważ (numer ostatniej wiadomości), URLHandler serwera odbiera je i dodaje wywołanie zwrotne, aby odpowiedzieć klientowi w kolejce.
Gdy serwer otrzymuje nową wiadomość, zdarzenie onmessage jest uruchamiane, zapętla wywołania zwrotne i wysyła wiadomości.
JS po stronie klienta odbiera komunikat, dodaje go do strony, a następnie prosi o aktualizacje, ponieważ ten nowy identyfikator wiadomości.
źródło
Myślę, że klient wygląda jak normalne asynchroniczne żądanie AJAX, ale oczekuje się, że powrót zajmie „dużo czasu”.
Serwer wygląda następująco.
Tak więc żądanie AJAX trafia do serwera, prawdopodobnie wraz ze znacznikiem czasu, kiedy była ostatnia aktualizacja,
hasNewData()
abyś wiedział, jakie dane już masz. Serwer następnie śpi w pętli, dopóki nowe dane nie będą dostępne. Przez cały czas twoje żądanie AJAX jest nadal połączone, po prostu czeka tam na dane. Wreszcie, gdy nowe dane są dostępne, serwer przekazuje je do żądania AJAX i zamyka połączenie.źródło
Oto kilka klas, których używam do długiego odpytywania w C #. Jest w zasadzie 6 klas (patrz poniżej).
źródło
To jest fajny 5-minutowy screencast na temat długiego odpytywania za pomocą PHP i jQuery: http://screenr.com/SNH
Kod jest dość podobny do powyższego przykładu dbr .
źródło
Oto prosty przykład długiego odpytywania w PHP autorstwa Erika Dubbelboera przy użyciu
Content-type: multipart/x-mixed-replace
nagłówka:A oto demo:
http://dubbelboer.com/multipart.php
źródło
Użyłem tego, aby poznać Comet, skonfigurowałem również Comet za pomocą serwera Java Glassfish i znalazłem wiele innych przykładów, subskrybując cometdaily.com
źródło
Spójrz na ten post na blogu, który zawiera kod prostej aplikacji do czatowania w Python / Django / gevent .
źródło
Poniżej znajduje się długie rozwiązanie ankietowe, które opracowałem dla Inform8 Web. Zasadniczo przesłonisz klasę i zaimplementujesz metodę loadData. Kiedy loadData zwróci wartość lub limit czasu operacji wydrukuje wynik i zwróci.
Jeśli przetwarzanie skryptu może potrwać dłużej niż 30 sekund, może być konieczne zmodyfikowanie wywołania set_time_limit () na coś dłuższego.
Licencja Apache 2.0. Najnowsza wersja na github https://github.com/ryanhend/Inform8/blob/master/Inform8-web/src/config/lib/Inform8/longpoll/LongPoller.php
Ryan
źródło
Dzięki za kod, dbr . Tylko mała literówka w long_poller.htm wokół linii
Myślę, że tak powinno być
aby działało.
Dla zainteresowanych wypróbowałem ekwiwalent Django. Rozpocznij nowy projekt Django, powiedz lp dla długiego odpytywania:
Zadzwoń do aplikacji msgsrv dla serwera wiadomości:
Dodaj następujące wiersze do settings.py, aby mieć katalog szablonów :
Zdefiniuj wzorce adresów URL w urls.py jako takie:
Plik msgsrv / views.py powinien wyglądać następująco:
Wreszcie, szablony / long_poller.htm powinny być takie same jak powyżej z poprawioną literówką. Mam nadzieję że to pomoże.
źródło
"15000"
jest to błąd składniowy. setTimeout przyjmuje liczbę całkowitą jako swój drugi parametr.Jest to jeden ze scenariuszy, dla których PHP jest bardzo złym wyborem. Jak wspomniano wcześniej, możesz bardzo szybko powiązać wszystkich pracowników Apache, robiąc coś takiego. PHP jest zbudowany do uruchamiania, wykonywania, zatrzymywania. Nie jest zbudowany na początek, poczekaj ... uruchom, zatrzymaj. Szybko zepsujesz serwer i przekonasz się, że masz niesamowite problemy ze skalowaniem.
To powiedziawszy, nadal możesz to zrobić za pomocą PHP i nie zabijaj swojego serwera za pomocą nginx HttpPushStreamModule: http://wiki.nginx.org/HttpPushStreamModule
Instalujesz nginx przed Apache (lub czymkolwiek innym), a on zajmie się utrzymywaniem otwartych równoczesnych połączeń. Po prostu odpowiadasz z ładunkiem, wysyłając dane na wewnętrzny adres, co możesz zrobić z zadaniem w tle lub po prostu wysyłać wiadomości do osób, które czekały za każdym razem, gdy nadejdą nowe żądania. Dzięki temu procesy PHP nie będą otwarte podczas długiego odpytywania.
Nie dotyczy to wyłącznie PHP i można to zrobić przy użyciu nginx z dowolnym językiem zaplecza. Obciążenie równoczesnych otwartych połączeń jest równe Node.js, więc największym atutem jest to, że wyciąga cię z POTRZEBUJĄCEGO węzła dla czegoś takiego.
Widzisz wiele innych osób, które wspominają o innych bibliotekach językowych w celu przeprowadzenia długiego odpytywania, i to nie bez powodu. PHP po prostu nie jest dobrze zbudowane do tego rodzaju zachowań.
źródło
Dlaczego nie rozważyć gniazd sieciowych zamiast długiego odpytywania? Są bardzo wydajne i łatwe w konfiguracji. Są one jednak obsługiwane tylko w nowoczesnych przeglądarkach. Oto krótkie odniesienie .
źródło
Grupa WS-I opublikowała coś o nazwie „Reliable Secure Profile”, który ma implementację Glass Fish i .NET, które najwyraźniej dobrze ze sobą współpracują .
Przy odrobinie szczęścia istnieje również implementacja Javascript .
Istnieje również implementacja Silverlight, która wykorzystuje HTTP Duplex. Możesz podłączyć javascript do obiektu Silverlight, aby uzyskać wywołania zwrotne, gdy nastąpi wypychanie.
Istnieją również komercyjne wersje płatne .
źródło
W przypadku implementacji ASP.NET MVC spójrz na SignalR, który jest dostępny na NuGet .. zauważ, że NuGet jest często nieaktualny ze źródła Git, które bardzo często popełnia zmiany.
Przeczytaj więcej o SignalR na blogu Scotta Hanselmana
źródło
Możesz wypróbować icomet ( https://github.com/ideawu/icomet ), serwer komet C1000K C ++ zbudowany z libevent. icomet zapewnia również bibliotekę JavaScript, jest łatwy w użyciu tak prosty jak
icomet obsługuje wiele przeglądarek i systemów operacyjnych, w tym Safari (iOS, Mac), IE (Windows), Firefox, Chrome itp.
źródło
Najprostszy NodeJS
Scenariusz mądry pod względem produkcyjnym w programie Express, na przykład
response
w oprogramowaniu pośrednim. Czy robisz to, co musisz zrobić, możesz objąć wszystkie długie ankietowane metody mapowaniem lub czymś (co jest widoczne dla innych przepływów) i wywoływać,<Response> response.end()
gdy będziesz gotowy. Nie ma nic specjalnego w długo odpytywanych połączeniach. Reszta to sposób, w jaki zwykle tworzysz strukturę aplikacji.Jeśli nie wiesz, co mam na myśli, określając zakres, powinno to dać ci pomysł
Jak widzisz, możesz naprawdę reagować na wszystkie połączenia, po pierwsze, rób co chcesz. Jest
id
na każde żądanie, więc powinieneś być w stanie korzystać z mapy i uzyskać dostęp do konkretnego połączenia poza interfejsem API.źródło