Wie implementiere ich grundlegende "Long Polling"?

776

Ich kann viele Informationen darüber finden, wie Long Polling funktioniert (zum Beispiel dies und das ), aber keine einfachen Beispiele, wie dies in Code implementiert wird.

Ich kann nur cometd finden , das auf dem Dojo JS-Framework basiert , und ein ziemlich komplexes Serversystem.

Wie würde ich Apache verwenden, um die Anforderungen zu bearbeiten, und wie würde ich ein einfaches Skript (z. B. in PHP) schreiben, das den Server lange nach neuen Nachrichten "abfragt"?

Das Beispiel muss nicht skalierbar, sicher oder vollständig sein, es muss nur funktionieren!

dbr
quelle

Antworten:

512

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.phpDatei. Wenn dies erfolgreich ist, #messageshä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 #messagesdiv 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.htmCode, 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>
dbr
quelle
7
Könnten mit dieser Idee nicht einige Nachrichten durchgehen? In dieser 1-Sekunden-Auszeit wurden beispielsweise 1000 Chat-Nachrichten gesendet. Woher weiß der Server, dass er die 1000 Nachrichten speziell an diesen Client sendet?
DevDevDev
15
Wahrscheinlich. Dies ist ein sehr vereinfachtes Beispiel, um das Konzept zu demonstrieren. Um dies besser zu machen, benötigen Sie einen ausgefeilteren serverseitigen Code, in dem die 1000 Nachrichten für diesen bestimmten Client gespeichert und in einem Block gesendet werden. Sie können auch das waitForMsg-Timeout
dbr
21
nodejs ist eine weitere hervorragende serverseitige Lösung für lange Abfrageanforderungen mit dem zusätzlichen Vorteil (gegenüber Twisted), dass Sie Servercode auch in Javascript schreiben können.
Husky
8
Dies ist nur eine einfache wiederkehrende AJAX-Verbindung zum Server mit einem Intervall von 1 Sekunde. Dies hat nichts mit "langem Polling" zu tun. Lange Abfragen sollten die Verbindung am Leben erhalten, solange das Client-Timeout auftritt.
Deele
6
Die Frage ist, was macht ein echtes PHP-Skript statt sleep(rand(2,10));? Um nichts zu tun, die Datenbank alle 100 Millisekunden abfragen? Wann entscheidet es sich zu sterben?
Luis Siquot
41

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.

<?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>
Dustin
quelle
1
Darf ich wissen, wie dies immer verbunden ist? Tut mir leid, wenn ich etwas Dummes frage, aber das möchte ich wissen.
Rocky Singh
4
Es führt ein HTTP-GET durch und der Server blockiert das GET, bis Daten verfügbar sind. Wenn Daten auf dem Server ankommen, gibt der Server die Daten an den Client zurück, stellt alle anderen eingehenden Daten in die Warteschlange und stellt dann die fehlenden Nachrichten wieder her und nimmt die fehlenden Nachrichten auf, andernfalls blockiert er sie erneut.
Dustin
4
Mag zunächst nicht offensichtlich sein, aber die Sache ist, dass AjaxStop mit getNewCommentsRückruf dort für den "immer verbundenen Zustand" verantwortlich ist , so dass es nur am Ende jeder Ajax-Anfrage endlos
ausgelöst wird
32

Tornado 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.

Mikemaccana
quelle
25

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.

while (!hasNewData())
    usleep(50);

outputNewData();

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.

Greg
quelle
10
Dies ist eine lange Wartezeit, die Ihren aktuellen Thread blockiert. Das skaliert überhaupt nicht.
Wouter Lievens
10
Nein, usleep ist kein geschäftiges Warten. Und der springende Punkt beim "Warten" ist, Ihren Thread für eine Weile zu blockieren. Wahrscheinlich meinte er 50 Millisekunden (usleep (50000)), nicht 50 Mikrosekunden! Aber gibt es bei einem typischen Apache / PHP-Setup eine andere Möglichkeit, dies zu tun?
Matt
Nach dem Prinzip können Sie eine Blockierungsfunktion für Chat-Nachrichten nicht ohne Wartezeit erstellen.
Tomáš Zato - Wiedereinsetzung Monica
Wirklich großartig! Ich habe eine rekursive Funktion im Server erstellt, um nach neuen Daten zu suchen. Aber was ist das beste Produkt, um die langen Abfragen effizient zu nutzen? Ich benutze den normalen Apache und der Server reagiert nicht, wenn ich mehr als 4/5 Browser-Registerkarten öffne :( Auf der Suche nach etwas, das mit PHP verwendet werden kann
moderns
17

Hier sind einige Klassen, die ich für lange Abfragen in C # verwende. Grundsätzlich gibt es 6 Klassen (siehe unten).

  1. Controller : Verarbeitet Aktionen, die zum Erstellen einer gültigen Antwort erforderlich sind (Datenbankoperationen usw.)
  2. Prozessor : Verwaltet die asynchrone Kommunikation mit der Webseite (selbst)
  3. IAsynchProcessor : Der Dienst verarbeitet Instanzen, die diese Schnittstelle implementieren
  4. Service : Verarbeitet Anforderungsobjekte, die IAsynchProcessor implementieren
  5. Anfrage : Der IAsynchProcessor-Wrapper mit Ihrer Antwort (Objekt)
  6. Antwort : Enthält benutzerdefinierte Objekte oder Felder
Gefangener NULL
quelle
2
Okay ... WARUM wurde das abgelehnt? Diese Klassen sind in der Tat gültige Beispiele für Langzeitabfragen.
Gefangener
Eine echte Langzeitabfrage ist nicht (einfach) die Praxis, das Intervall zu verlängern, in dem Sie eine normale Abfrage (für eine Ressource) durchführen. Es ist Teil eines größeren Musters ... das "etwas" interpretiert werden kann ... aber nur in bestimmten Bereichen der Gesamtimplementierung. Das heißt ... diese Klassen folgen diesem Muster! Wenn Sie also einen Grund haben, dies abzulehnen ... würde mich der Grund wirklich interessieren.
Gefangener NULL
Vielleicht wurde es abgelehnt, da es die Frage eines einfachen Codebeispiels nicht direkt anspricht. Natürlich habe ich es nicht abgelehnt, also kann ich nur raten.
Andrew
16

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 .

Sean O.
quelle
3
Ich denke, Sie sollten dies nur als Einführung in Long-Polling betrachten, da diese Implementierung Ihren Server mit vielen gleichzeitigen Benutzern mit Sicherheit töten wird.
Alfred
Ich lerne gerade über all das ... wie zuverlässig oder nicht, ist es mit ein paar Benutzern ... sagen wir 10 Chatten hin und her?
Irgendwann am
12

Hier ist ein einfaches Beispiel für lange Abfragen in PHP von Erik Dubbelboer unter Verwendung des Content-type: multipart/x-mixed-replaceHeaders:

<?

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
';

Und hier ist eine Demo:

http://dubbelboer.com/multipart.php

Jasdeep Khalsa
quelle
11

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

Adam
quelle
9

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

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

}
Ryan Henderson
quelle
8

Danke für den Code, dbr . Nur ein kleiner Tippfehler in long_poller.htm um die Zeile

1000 /* ..after 1 seconds */

Ich denke es sollte sein

"1000"); /* ..after 1 seconds */

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:

django-admin.py startproject lp

Rufen Sie die App msgsrv für den Nachrichtenserver auf:

python manage.py startapp msgsrv

Fügen Sie settings.py die folgenden Zeilen hinzu , um ein Vorlagenverzeichnis zu haben :

import os.path
PROJECT_DIR = os.path.dirname(__file__)
TEMPLATE_DIRS = (
    os.path.join(PROJECT_DIR, 'templates'),
)

Definieren Sie Ihre URL-Muster in urls.py als solche:

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'}),
)

Und msgsrv / views.py sollte folgendermaßen aussehen:

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

Schließlich sollte templates / long_poller.htm mit Tippfehler korrigiert sein. Hoffe das hilft.

xoblau
quelle
Eigentlich "15000"ist der Syntaxfehler. setTimeout verwendet eine Ganzzahl als zweiten Parameter.
Andrew Hedges
Diese Antwort braucht Arbeit. Es ist der Höhepunkt eines oder mehrerer Kommentare und einer separaten Antwort oder Antworten.
Brian Webster
8

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.

Brightball
quelle
Ist das ein Apache-Problem oder ein PHP-Problem? Hätte ich Probleme mit langen Abfragen, wenn mein PHP-Code direkt auf nginx oder lighttpd ausgeführt würde?
David
Es ist weniger ein PHP-Problem als vielmehr ein PHP-Missbrauch. Bei jeder Anforderung führt PHP das Skript von Grund auf neu aus, lädt Bibliotheken nach Bedarf, führt den Code aus und fährt dann herunter, während die Speicherbereinigung alles beginnt, was in der Anforderung gestartet wurde. Im Laufe der Jahre wurden viele Änderungen an PHP vorgenommen, um die Auswirkungen wie verspätete statische Bindungen, verzögertes Laden, Speicher-Bytecode-Caches zum Entfernen von Festplatten-E / A usw. zu minimieren. Das Problem besteht weiterhin darin, dass PHP so schnell gestartet und gestoppt werden soll wie möglich. Sprachen, die einmal geladen / gebootet und ein Thread für die Anforderung geöffnet werden, eignen sich viel besser für lange Abfragen.
Brightball
Aber um die Frage zu beantworten: Ja, das Problem tritt auf, unabhängig davon, ob Sie Apache oder etwas anderes verwenden. So funktioniert PHP. Ich sollte dies dahingehend ändern, dass PHP in Ordnung ist, wenn Sie eine bekannte maximale Verkehrslast haben. Ich habe eingebettete Systeme mit PHP gesehen, die keine Probleme haben, da es nur ein paar Verbindungen gibt. Möglicherweise in einem Unternehmens-Intranet könnte dies auch passabel sein. Bei öffentlich zugänglichen Anwendungen werden Sie Ihre Server jedoch mit zunehmendem Datenverkehr unbedingt töten.
Brightball
4

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 .

Shasi Kanth
quelle
Ich denke, sobald Websockets überall implementiert sind (wahrscheinlich nicht für die kommenden Jahre), werden sie der Standard für diese Art von Anwendung sein. Leider können wir uns derzeit nicht auf sie für Produktions-Apps verlassen.
Richard
3
@Richard Sie können jedoch so etwas wie Socket.IO verwenden, das automatische Fallback-Transporte bietet und Web-Socket-ähnliche Funktionen bis hinunter zu IE 6 bietet.
Brad
3

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 .

goodguys_activate
quelle
2

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

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 unterstützt eine Vielzahl von Browsern und Betriebssystemen, darunter Safari (iOS, Mac), IEs (Windows), Firefox, Chrome usw.

ideawu
quelle
0

Einfachster KnotenJS

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

Produktionsbezogenes Szenario in Express zum Beispiel, das Sie responsein 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

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

Wie Sie sehen, können Sie wirklich auf alle Verbindungen reagieren, eine, tun, was Sie wollen. Es gibt idfür jede Anfrage, so dass Sie in der Lage sein sollten, Karte zu verwenden und auf bestimmte Out-of-API-Anrufe zuzugreifen.

sp3c1
quelle