Jak zaimplementować podstawowe "Długie ankiety"?
Mogę znaleźć wiele informacji na temat tego, jak długo działa ankieta (na przykład, this i this), ale nie proste przykłady jak zaimplementować to w kodzie.
Jedyne co mogę znaleźć tocometd , który opiera się na frameworku Dojo JS i dość skomplikowanym systemie serwerowym..
Zasadniczo, jak używać Apache do obsługi żądań, i jak napisać prosty skrypt (powiedzmy, w PHP), który "długo ankieta" serwer dla nowych wiadomości?
The przykład nie musi być skalowalny, Bezpieczny lub kompletny, po prostu musi działać!
18 answers
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 pojawi się nowa wiadomość).
Oto naprawdę podstawowy przykład, który wysyła prosty ciąg po 2-10 sekundach. 1 na 3 szansa 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 przypadku prawdziwej strony, uruchomienie tego na zwykłym serwerze internetowym, takim jak Apache, szybko połączy wszystkie "wątki robocze" i pozostawić go w stanie odpowiedzieć na inne żądania.. Istnieją sposoby na obejście tego, ale zaleca się napisanie "serwera long-poll" w czymś takim jak Python twisted, który nie opiera się na jednym wątku na żądanie. cometD jest popularnym frameworkiem (dostępnym w kilku językach), a Tornado jest nowym frameworkiem stworzonym specjalnie do takich zadań (został zbudowany na potrzeby kodu Long-polling FriendFeed)... ale jako prosty przykład, Apache jest czymś więcej niż / align = "left" / Ten skrypt może być łatwo napisany w dowolnym języku (wybrałem Apache/PHP, ponieważ są one bardzo powszechne i zdarzyło mi się uruchamiać je lokalnie)
Następnie, w Javascript, żądasz powyższego pliku (msg_srv.php
) i czekasz na odpowiedź. Kiedy je zdobędziesz, działasz na podstawie danych. Następnie żądasz pliku i czekasz ponownie, działaj na dane (i powtarzaj)
Poniżej znajduje się przykład takiej strony.. Po załadowaniu strony wysyła początkowe żądanie pliku msgsrv.php
.. Jeśli to jeśli się powiedzie, dodajemy wiadomość do #messages
div, po 1 sekundzie ponownie wywołujemy funkcję waitForMsg, która uruchamia wait.
1 sekunda setTimeout()
jest naprawdę podstawowym ogranicznikiem szybkości, działa bez tego dobrze, ale jeśli msgsrv.php
zawsze powraca natychmiast (np. z błędem składni) - zalewasz przeglądarkę i może ona szybko się zawiesić. Lepiej zrobić to sprawdzając, czy plik zawiera poprawną odpowiedź JSON i / lub zachowując działającą sumę żądania-na minutę/sekundę i odpowiednio wstrzymuje.
Jeśli strona jest błędna, dopisze błąd do #messages
div, czeka 15 sekund, a następnie próbuje ponownie (identycznie jak czekamy 1 sekundę po każdej wiadomości)
Fajną rzeczą w tym podejściu jest to, że jest bardzo odporne. Jeśli połączenie internetowe klienta umrze, nastąpi timeout, a następnie spróbuj ponownie się połączyć-jest to nieodłączne od tego, jak długo działa ankieta, nie jest wymagana skomplikowana obsługa błędów]}
W każdym razie, long_poller.htm
Kod, korzystanie z 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>
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
2012-10-01 11:24:47
Mam bardzo prosty przykład czatu w ramach slosh .
Edit : (skoro wszyscy wklejają tu swój kod)
Jest to kompletny chat wieloosobowy oparty na JSON, wykorzystujący long-polling i slosh . To jest demo Jak wykonywać połączenia, więc proszę zignorować problemy z XSS. Nikt nie powinien tego instalować bez uprzedniego dezynfekcji.
Zauważ, że klient zawsze ma połączenie z serwerem i jak tylko ktoś wyśle wiadomość, każdy powinien zobaczyć ją mniej więcej natychmiast.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- Copyright (c) 2008 Dustin Sallings <[email protected]> -->
<html lang="en">
<head>
<title>slosh chat</title>
<script type="text/javascript"
src="http://code.jquery.com/jquery-latest.js"></script>
<link title="Default" rel="stylesheet" media="screen" href="style.css" />
</head>
<body>
<h1>Welcome to Slosh Chat</h1>
<div id="messages">
<div>
<span class="from">First!:</span>
<span class="msg">Welcome to chat. Please don't hurt each other.</span>
</div>
</div>
<form method="post" action="#">
<div>Nick: <input id='from' type="text" name="from"/></div>
<div>Message:</div>
<div><textarea id='msg' name="msg"></textarea></div>
<div><input type="submit" value="Say it" id="submit"/></div>
</form>
<script type="text/javascript">
function gotData(json, st) {
var msgs=$('#messages');
$.each(json.res, function(idx, p) {
var from = p.from[0]
var msg = p.msg[0]
msgs.append("<div><span class='from'>" + from + ":</span>" +
" <span class='msg'>" + msg + "</span></div>");
});
// The jQuery wrapped msgs above does not work here.
var msgs=document.getElementById("messages");
msgs.scrollTop = msgs.scrollHeight;
}
function getNewComments() {
$.getJSON('/topics/chat.json', gotData);
}
$(document).ready(function() {
$(document).ajaxStop(getNewComments);
$("form").submit(function() {
$.post('/topics/chat', $('form').serialize());
return false;
});
getNewComments();
});
</script>
</body>
</html>
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
2012-06-04 08:22:44
Tornado jest przeznaczone do długiego sondowania i zawiera bardzo minimalną (kilkaset linii Pythona) aplikację do czatu w / examples / chatdemo , w tym kod serwera i Kod klienta JS. Działa tak:
Klienci używają JS, aby poprosić o aktualizację od (liczba ostatniej wiadomości), server URLHandler odbiera te i dodaje callback, aby odpowiedzieć na klienta do kolejki.
Gdy serwer otrzyma nową wiadomość, zostanie wywołane zdarzenie onmessage, zapętla połączenia zwrotne i wysyła wiadomości.
JS po stronie klienta otrzymuje wiadomość, dodaje ją do strony, a następnie prosi o aktualizacje od tego nowego identyfikatora wiadomości.
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-05-16 13:33:59
Myślę, że klient wygląda jak normalne asynchroniczne żądanie AJAX, ale spodziewasz się, że powrót zajmie "dużo czasu".
Serwer wygląda więc tak.
while (!hasNewData())
usleep(50);
outputNewData();
Więc, żądanie AJAX idzie do serwera, prawdopodobnie w tym znacznik czasu, kiedy była ostatnia aktualizacja tak, że hasNewData()
wie, jakie dane już masz.
Następnie serwer siedzi w pętli uśpionej, dopóki nie będą dostępne nowe dane. Cały czas, żądanie AJAX jest nadal podłączony, po prostu wisi tam czeka na data.
Wreszcie, gdy nowe dane są dostępne, serwer przekazuje je do żądania AJAX i zamyka połączenie.
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
2008-12-02 11:39:37
Proszę. czy są jakieś klasy, których używam do długich ankiet w C#. Istnieje zasadniczo 6 klas(patrz poniżej).
- Controller : przetwarza akcje wymagane do utworzenia prawidłowej odpowiedzi (operacje db itp.)
- Procesor : zarządza komunikacją asynchroniczną ze stroną www (samą w sobie)
- IAsynchProcessor : usługa przetwarza instancje implementujące ten interfejs
- Sevice : przetwarza obiekty żądające, które implementują IAsynchProcessor
- Request : wrapper IAsynchProcessor zawierający twoją odpowiedź (obiekt)
- Response: zawiera niestandardowe obiekty lub pola
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-05-23 11:54:41
To jest fajny 5-minutowy screencast jak zrobić długie ankiety przy użyciu PHP & jQuery: http://screenr.com/SNH
KodJest bardzo podobny do przykładu dbr powyżej.
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
2009-10-20 15:41:38
Oto prosty przykład long-polling w PHP autorstwa Erika Dubbelboera używając nagłówka Content-type: multipart/x-mixed-replace
:
<?
header('Content-type: multipart/x-mixed-replace; boundary=endofsection');
// Keep in mind that the empty line is important to separate the headers
// from the content.
echo 'Content-type: text/plain
After 5 seconds this will go away and a cat will appear...
--endofsection
';
flush(); // Don't forget to flush the content to the browser.
sleep(5);
echo 'Content-type: image/jpg
';
$stream = fopen('cat.jpg', 'rb');
fpassthru($stream);
fclose($stream);
echo '
--endofsection
';
A oto demo:
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
2012-12-08 12:29:21
Użyłem tego aby uporać się z Comet, skonfigurowałem również Comet używając serwera Java Glassfish i znalazłem wiele innych przykładów subskrybując cometdaily.com
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
2008-12-02 11:21:34
Poniżej znajduje się długie rozwiązanie ankietowe, które opracowałem dla Inform8 Web. Zasadniczo nadpisujesz klasę i zaimplementujesz metodę loadData. Gdy loadData zwróci wartość lub czas operacji się skończy, wydrukuje wynik i zwróci.
Jeśli przetwarzanie skryptu może trwać dłużej niż 30 sekund, może być konieczna zmiana 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
abstract class LongPoller {
protected $sleepTime = 5;
protected $timeoutTime = 30;
function __construct() {
}
function setTimeout($timeout) {
$this->timeoutTime = $timeout;
}
function setSleep($sleep) {
$this->sleepTime = $sleepTime;
}
public function run() {
$data = NULL;
$timeout = 0;
set_time_limit($this->timeoutTime + $this->sleepTime + 15);
//Query database for data
while($data == NULL && $timeout < $this->timeoutTime) {
$data = $this->loadData();
if($data == NULL){
//No new orders, flush to notify php still alive
flush();
//Wait for new Messages
sleep($this->sleepTime);
$timeout += $this->sleepTime;
}else{
echo $data;
flush();
}
}
}
protected abstract function loadData();
}
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
2011-05-05 10:39:24
Dzięki za kod, dbr . Mała literówka w long_poller.htm wokół linii
1000 /* ..after 1 seconds */
Myślę, że powinno być
"1000"); /* ..after 1 seconds */
Żeby zadziałało.
Dla zainteresowanych wypróbowałem odpowiednik Django. Rozpocznij nowy projekt Django, powiedzmy na za długie głosowanie:
django-admin.py startproject lp
Wywołanie aplikacji msgsrv dla serwera wiadomości:
python manage.py startapp msgsrv
Dodaj następujące wiersze do settings.py aby mieć szablony katalog:
import os.path
PROJECT_DIR = os.path.dirname(__file__)
TEMPLATE_DIRS = (
os.path.join(PROJECT_DIR, 'templates'),
)
Zdefiniuj wzorce URL w urls.py jako takie:
from django.views.generic.simple import direct_to_template
from lp.msgsrv.views import retmsg
urlpatterns = patterns('',
(r'^msgsrv\.php$', retmsg),
(r'^long_poller\.htm$', direct_to_template, {'template': 'long_poller.htm'}),
)
I msgsrv / views.py powinno wyglądać tak:
from random import randint
from time import sleep
from django.http import HttpResponse, HttpResponseNotFound
def retmsg(request):
if randint(1,3) == 1:
return HttpResponseNotFound('<h1>Page not found</h1>')
else:
sleep(randint(2,10))
return HttpResponse('Hi! Have a random number: %s' % str(randint(1,10)))
Wreszcie, templates / long_poller.htm powinien być taki sam jak powyżej z poprawką literówki. Mam nadzieję, że to pomoże.
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
2009-09-15 12:30:50
Spójrz na ten wpis na blogu , który zawiera kod dla prostej aplikacji do czatu w Pythonie/Django/gevent .
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
2010-07-30 00:07:25
Jest to jeden ze scenariuszy, dla których PHP jest bardzo złym wyborem. Jak wcześniej wspomniano, możesz bardzo szybko związać wszystkich swoich pracowników Apache, robiąc coś takiego. PHP jest zbudowany dla start, execute, stop. Nie jest zbudowany na początek, czekaj...wykonać, zatrzymać się. Bardzo szybko zniszczysz swój serwer i przekonasz się, że masz niesamowite problemy ze skalowaniem.
To powiedziawszy, nadal możesz to zrobić z PHP i nie zabić serwera za pomocą nginx HttpPushStreamModule: http://wiki.nginx.org/HttpPushStreamModule
Skonfigurujesz nginx przed Apache ' em (czy czymkolwiek innym), a on zajmie się utrzymywaniem połączeń współbieżnych. Po prostu odpowiadasz ładunkiem, wysyłając dane na adres wewnętrzny, który możesz zrobić w tle lub po prostu odpalać Wiadomości do osób, które czekały, gdy pojawią się nowe żądania. Dzięki temu procesy PHP nie są otwarte podczas długiego sondowania.
To nie jest wyłącznie PHP i można to zrobić za pomocą nginx z dowolnym językiem zaplecza. Obciążenie współbieżnych połączeń otwartych jest równe Node.js więc największym plusem jest to, że wyciąga cię z konieczności węzła do czegoś takiego.
Widzisz wiele innych osób, które wspominają o innych bibliotekach językowych dla przeprowadzenia długich ankiet i to nie bez powodu. PHP nie jest po prostu dobrze zbudowany dla tego typu zachowań naturalnie.
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-04-09 17:54:34
Tutaj jest węzeł.przykład js dostarczany z klientem jquery. Jest też instrukcja ustawienia go na heroku.
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-03-04 03:37:10
Dlaczego nie wziąć pod uwagę gniazd sieciowych zamiast długich sondaży? Są bardzo wydajne i łatwe w konfiguracji. Jednak są one obsługiwane tylko w nowoczesnych przeglądarkach. Oto szybka Referencja.
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-05-23 12:18:14
Grupa ws-i opublikowała coś o nazwie "niezawodny bezpieczny Profil", który ma szklaną rybę i implementację.NET, która najwyraźniej współdziała dobrze.
Przy odrobinie szczęścia istnieje również implementacjaJavascript .
Istnieje również implementacja Silverlight, która używa dupleksu HTTP. możesz podłączyć javascript do obiektu Silverlight , aby uzyskać wywołania zwrotne, gdy wystąpi push.
Są też komercyjne płatne wersje jak również.
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-05-23 11:47:19
Dla a ASP.NET implementacja 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 otrzymuje bardzo częste commity.
Więcej o SignalR przeczytasz na blogu Scotta HanselmanaWarning: 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
2012-02-09 17:14:13
Możesz spróbować icomet ( https://github.com/ideawu/icomet ), c1000k C++ Comet server 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.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-10-01 02:19:56
Najprostsze NodeJS
const http = require('http');
const server = http.createServer((req, res) => {
SomeVeryLongAction(res);
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);
// the long running task - simplified to setTimeout here
// but can be async, wait from websocket service - whatever really
function SomeVeryLongAction(response) {
setTimeout(response.end, 10000);
}
Scenariusz produkcji w Expressie dla exmaple otrzymałbyś response
w middleware. Zrób to, co musisz zrobić, możesz sprawdzić wszystkie długo ankietowane metody mapowania lub coś (co jest widoczne dla innych przepływów) i wywołać <Response> response.end()
, Gdy jesteś gotowy. Nie ma nic specjalnego w długich ankietowanych połączeniach. Reszta jest taka, jak zwykle struktura aplikacji.
Jeśli nie wiesz, o co mi chodzi, to powinno dać ci idea
const http = require('http');
var responsesArray = [];
const server = http.createServer((req, res) => {
// not dealing with connection
// put it on stack (array in this case)
responsesArray.push(res);
// end this is where normal api flow ends
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
// and eventually when we are ready to resolve
// that if is there just to ensure you actually
// called endpoint before the timeout kicks in
function SomeVeryLongAction() {
if ( responsesArray.length ) {
let localResponse = responsesArray.shift();
localResponse.end();
}
}
// simulate some action out of endpoint flow
setTimeout(SomeVeryLongAction, 10000);
server.listen(8000);
Jak widzisz, możesz naprawdę reagować na wszystkie połączenia, po pierwsze, robić, co chcesz. Istnieje id
dla każdego żądania, więc powinieneś być w stanie korzystać z mapy i dostępu określonego z wywołania api.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-05-04 10:50:35