Es ist einfacher als ich ursprünglich dachte. Grundsätzlich haben Sie eine Seite, die nichts tut, bis die Daten, die Sie senden möchten, verfügbar sind (z. B. eine neue Nachricht eintrifft).
Hier ist ein wirklich einfaches Beispiel, das nach 2-10 Sekunden eine einfache Zeichenfolge sendet. 1: 3-Chance, einen Fehler 404 zurückzugeben (um die Fehlerbehandlung im kommenden Javascript-Beispiel zu zeigen)
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));
?>
Hinweis: Wenn Sie dies auf einer realen Site auf einem normalen Webserver wie Apache ausführen, werden schnell alle "Arbeitsthreads" gebunden, sodass andere Anfragen nicht beantwortet werden können. Es gibt Möglichkeiten, dies zu umgehen, es wird jedoch empfohlen, zu schreiben Ein "Long-Poll-Server" in so etwas wie Pythons Twisted , der nicht auf einen Thread pro Anfrage angewiesen ist. cometD ist ein beliebtes Framework (das in mehreren Sprachen verfügbar ist), und Tornado ist ein neues Framework, das speziell für solche Aufgaben entwickelt wurde (es wurde für FriendFeeds Code für lange Abfragen entwickelt). Als einfaches Beispiel ist Apache jedoch mehr als ausreichend ! Dieses Skript kann leicht in jeder Sprache geschrieben werden (ich habe Apache / PHP gewählt, da sie sehr häufig sind, und ich habe sie zufällig lokal ausgeführt).
Anschließend fordern Sie in Javascript die obige Datei ( msg_srv.php
) an und warten auf eine Antwort. Wenn Sie eine bekommen, reagieren Sie auf die Daten. Dann fordern Sie die Datei an und warten erneut, reagieren auf die Daten (und wiederholen)
Was folgt, ist ein Beispiel für eine solche Seite. Wenn die Seite geladen wird, sendet sie die erste Anforderung für die msgsrv.php
Datei. Wenn dies erfolgreich ist, #messages
hängen wir die Nachricht an das div an und rufen nach 1 Sekunde die Funktion waitForMsg erneut auf. was das Warten auslöst.
Die 1 Sekunde setTimeout()
ist ein wirklich grundlegender Ratenbegrenzer. Ohne diese Funktion funktioniert sie einwandfrei. Wenn sie jedoch msgsrv.php
immer sofort zurückgegeben wird (z. B. mit einem Syntaxfehler), wird der Browser überflutet und er kann schnell einfrieren. Dies sollte besser überprüft werden, ob die Datei eine gültige JSON-Antwort enthält, und / oder eine laufende Summe von Anforderungen pro Minute / Sekunde beibehalten und entsprechend angehalten werden.
Wenn die Seite fehlerhaft ist, hängt sie den Fehler an das #messages
div an, wartet 15 Sekunden und versucht es dann erneut (identisch damit, wie wir nach jeder Nachricht 1 Sekunde warten).
Das Schöne an diesem Ansatz ist, dass er sehr belastbar ist. Wenn die Internetverbindung des Clients unterbrochen wird, tritt eine Zeitüberschreitung auf. Versuchen Sie dann erneut, die Verbindung herzustellen. Dies hängt davon ab, wie lange das Abrufen funktioniert. Es ist keine komplizierte Fehlerbehandlung erforderlich
Wie auch immer, der long_poller.htm
Code, der das jQuery-Framework verwendet:
<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));
? Um nichts zu tun, die Datenbank alle 100 Millisekunden abfragen? Wann entscheidet es sich zu sterben?Ich habe ein wirklich einfaches Chat-Beispiel als Teil von Slosh .
Bearbeiten : (da jeder seinen Code hier einfügt)
Dies ist der vollständige JSON-basierte Mehrbenutzer-Chat mit Long-Polling und Slosh . Dies ist eine Demo zum Ausführen der Anrufe. Ignorieren Sie daher die XSS-Probleme. Niemand sollte dies bereitstellen, ohne es vorher zu bereinigen.
Beachten Sie, dass der Client immer eine Verbindung zum Server hat. Sobald jemand eine Nachricht sendet, sollte jeder sie ungefähr sofort sehen.
quelle
getNewComments
Rückruf dort für den "immer verbundenen Zustand" verantwortlich ist , so dass es nur am Ende jeder Ajax-Anfrage endlosTornado wurde für lange Abfragen entwickelt und enthält eine sehr minimale (einige hundert Zeilen Python) Chat-App in / examples / chatdemo , einschließlich Servercode und JS-Clientcode. Es funktioniert so:
Clients verwenden JS, um nach Updates zu fragen, da (Nummer der letzten Nachricht) der Server-URLHandler diese empfängt und einen Rückruf hinzufügt, um dem Client auf eine Warteschlange zu antworten.
Wenn der Server eine neue Nachricht erhält, wird das Ereignis onmessage ausgelöst, durchläuft die Rückrufe und sendet die Nachrichten.
Der clientseitige JS empfängt die Nachricht, fügt sie der Seite hinzu und fordert seit dieser neuen Nachrichten-ID Aktualisierungen an.
quelle
Ich denke, der Client sieht aus wie eine normale asynchrone AJAX-Anfrage, aber Sie erwarten, dass es "lange" dauert, bis er zurückkommt.
Der Server sieht dann so aus.
Die AJAX-Anforderung wird also an den Server gesendet, wahrscheinlich mit einem Zeitstempel des letzten Updates, damit Sie
hasNewData()
wissen, welche Daten Sie bereits haben. Der Server befindet sich dann in einer Schleife, bis neue Daten verfügbar sind. Währenddessen ist Ihre AJAX-Anfrage immer noch verbunden und wartet nur auf Daten. Wenn neue Daten verfügbar sind, gibt der Server diese an Ihre AJAX-Anfrage weiter und schließt die Verbindung.quelle
Hier sind einige Klassen, die ich für lange Abfragen in C # verwende. Grundsätzlich gibt es 6 Klassen (siehe unten).
quelle
Dies ist ein schöner 5-minütiger Screencast darüber, wie man mit PHP & jQuery lange Abfragen durchführt: http://screenr.com/SNH
Der Code ist dem obigen Beispiel von dbr ziemlich ähnlich .
quelle
Hier ist ein einfaches Beispiel für lange Abfragen in PHP von Erik Dubbelboer unter Verwendung des
Content-type: multipart/x-mixed-replace
Headers:Und hier ist eine Demo:
http://dubbelboer.com/multipart.php
quelle
Ich habe dies verwendet , um Comet in den Griff zu bekommen. Ich habe Comet auch über den Java Glassfish-Server eingerichtet und viele andere Beispiele gefunden, indem ich cometdaily.com abonniert habe
quelle
Schauen Sie sich diesen Blog-Beitrag an, der Code für eine einfache Chat-App in Python / Django / gevent enthält .
quelle
Im Folgenden finden Sie eine lange Abfragelösung, die ich für Inform8 Web entwickelt habe. Grundsätzlich überschreiben Sie die Klasse und implementieren die loadData-Methode. Wenn loadData einen Wert zurückgibt oder die Operation eine Zeitüberschreitung aufweist, wird das Ergebnis gedruckt und zurückgegeben.
Wenn die Verarbeitung Ihres Skripts länger als 30 Sekunden dauert, müssen Sie möglicherweise den Aufruf von set_time_limit () auf etwas längeres ändern.
Apache 2.0 Lizenz. Neueste Version auf github https://github.com/ryanhend/Inform8/blob/master/Inform8-web/src/config/lib/Inform8/longpoll/LongPoller.php
Ryan
quelle
Danke für den Code, dbr . Nur ein kleiner Tippfehler in long_poller.htm um die Zeile
Ich denke es sollte sein
damit es funktioniert.
Für Interessierte habe ich ein Django-Äquivalent ausprobiert. Starten Sie ein neues Django-Projekt, sagen Sie lp für lange Abstimmungen:
Rufen Sie die App msgsrv für den Nachrichtenserver auf:
Fügen Sie settings.py die folgenden Zeilen hinzu , um ein Vorlagenverzeichnis zu haben :
Definieren Sie Ihre URL-Muster in urls.py als solche:
Und msgsrv / views.py sollte folgendermaßen aussehen:
Schließlich sollte templates / long_poller.htm mit Tippfehler korrigiert sein. Hoffe das hilft.
quelle
"15000"
ist der Syntaxfehler. setTimeout verwendet eine Ganzzahl als zweiten Parameter.Dies ist eines der Szenarien, für die PHP eine sehr schlechte Wahl ist. Wie bereits erwähnt, können Sie alle Ihre Apache-Mitarbeiter sehr schnell mit so etwas verbinden. PHP wurde zum Starten, Ausführen und Stoppen entwickelt. Es ist nicht für Start, Warten ... Ausführen, Stoppen gebaut. Sie werden Ihren Server sehr schnell blockieren und feststellen, dass Sie unglaubliche Skalierungsprobleme haben.
Das heißt, Sie können dies immer noch mit PHP tun und Ihren Server nicht mit dem nginx HttpPushStreamModule töten lassen: http://wiki.nginx.org/HttpPushStreamModule
Sie richten nginx vor Apache (oder was auch immer) ein und es sorgt dafür, dass die gleichzeitigen Verbindungen offen bleiben. Sie antworten einfach mit Nutzdaten, indem Sie Daten an eine interne Adresse senden, die Sie mit einem Hintergrundjob erledigen könnten, oder die Nachrichten einfach an Personen abfeuern lassen, die warten, wenn die neuen Anforderungen eingehen. Dies verhindert, dass PHP-Prozesse während langer Abfragen geöffnet bleiben.
Dies ist nicht exklusiv für PHP und kann mit nginx mit jeder Backend-Sprache durchgeführt werden. Die gleichzeitige Last offener Verbindungen entspricht Node.js, sodass der größte Vorteil darin besteht, dass Sie für so etwas aus dem NOTWENDIGEN Node herauskommen.
Sie sehen viele andere Leute, die andere Sprachbibliotheken erwähnen, um lange Abstimmungen durchzuführen, und das aus gutem Grund. PHP ist für diese Art von Verhalten natürlich nicht gut entwickelt.
quelle
Warum nicht die Web-Sockets in Betracht ziehen, anstatt lange Abfragen durchzuführen? Sie sind sehr effizient und einfach einzurichten. Sie werden jedoch nur in modernen Browsern unterstützt. Hier ist eine Kurzreferenz .
quelle
Die WS-I - Gruppe veröffentlicht etwas namens „Zuverlässig Sicher Profil“ , das eine Glasfische und hat .NET - Implementierung , dass scheinbar inter funktionieren gut.
Mit etwas Glück gibt es auch eine Javascript- Implementierung.
Es gibt auch eine Silverlight-Implementierung, die HTTP-Duplex verwendet. Sie können Javascript mit dem Silverlight- Objekt verbinden, um Rückrufe zu erhalten, wenn ein Push auftritt.
Es gibt auch kommerzielle kostenpflichtige Versionen .
quelle
Sehen Sie sich für eine ASP.NET MVC-Implementierung SignalR an, das auf NuGet verfügbar ist . Beachten Sie, dass das NuGet von der Git-Quelle, die sehr häufig festgeschrieben wird, häufig veraltet ist .
Lesen Sie mehr über SignalR in einem Blog von Scott Hanselman
quelle
Sie können icomet ( https://github.com/ideawu/icomet ) ausprobieren , einen C1000K C ++ - Kometenserver, der mit libevent erstellt wurde. icomet bietet auch eine JavaScript-Bibliothek, die so einfach wie möglich zu bedienen ist
icomet unterstützt eine Vielzahl von Browsern und Betriebssystemen, darunter Safari (iOS, Mac), IEs (Windows), Firefox, Chrome usw.
quelle
Einfachster KnotenJS
Produktionsbezogenes Szenario in Express zum Beispiel, das Sie
response
in der Middleware erhalten würden. Wenn Sie das tun, was Sie tun müssen, können Sie alle lang abgefragten Methoden auf Map oder etwas anderes (das für andere Flows sichtbar ist) ausdehnen und aufrufen,<Response> response.end()
wann immer Sie bereit sind. Lange abgefragte Verbindungen haben nichts Besonderes. Ruhe ist genau so, wie Sie Ihre Anwendung normalerweise strukturieren.Wenn Sie nicht wissen, was ich mit Scoping meine, sollte dies Ihnen eine Idee geben
Wie Sie sehen, können Sie wirklich auf alle Verbindungen reagieren, eine, tun, was Sie wollen. Es gibt
id
für jede Anfrage, so dass Sie in der Lage sein sollten, Karte zu verwenden und auf bestimmte Out-of-API-Anrufe zuzugreifen.quelle