Frage Wie implementiere ich Basic "Long Polling"?


Ich kann viele Informationen darüber finden, wie Long Polling funktioniert (z. B. Dies, und Dies), aber nein einfach Beispiele, wie dies im Code implementiert werden kann.

Alles was ich finden kann ist Kometd, die auf dem Dojo JS-Framework und einem ziemlich komplexen Serversystem beruht.

Im Grunde, wie würde ich Apache verwenden, um die Anfragen zu bedienen, und wie würde ich ein einfaches Skript schreiben (sagen wir in PHP), das den Server nach neuen Nachrichten "lang-poll"?

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


744
2017-12-02 11:14


Ursprung


Antworten:


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 ist (sagen wir, eine neue Nachricht kommt an).

Hier ist ein wirklich einfaches Beispiel, das nach 2 bis 10 Sekunden eine einfache Zeichenfolge sendet. 1 von 3 Chance, einen Fehler 404 zurückzugeben (um die Fehlerbehandlung im folgenden Javascript-Beispiel anzuzeigen)

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: Bei einer echten Site bindet das Ausführen auf einem regulären Webserver wie Apache schnell alle "Arbeitsthreads" ein und lässt sie nicht auf andere Anfragen reagieren. Es gibt verschiedene Möglichkeiten, aber es wird empfohlen zu schreiben ein "Long-Poll-Server" in etwas wie Pythons verdrehte, die nicht auf einen Thread pro Anfrage angewiesen ist. KometD ist eine beliebte (die in mehreren Sprachen verfügbar ist), und Tornado ist ein neues Framework speziell für solche Aufgaben (es wurde für FriendFeed Long-Polling-Code erstellt) ... aber als einfaches Beispiel ist Apache mehr als ausreichend! Dieses Skript könnte leicht in jeder Sprache geschrieben werden (ich habe mich für Apache / PHP entschieden, da sie sehr häufig verwendet werden und ich habe sie lokal ausgeführt)

Dann fordern Sie in Javascript die oben genannte Datei an (msg_srv.php) und warte auf eine Antwort. Wenn Sie einen bekommen, handeln Sie nach den Daten. Dann fordern Sie die Datei an und warten Sie erneut, handeln Sie mit den Daten (und wiederholen Sie)

Was folgt, ist ein Beispiel für eine solche Seite. Wenn die Seite geladen ist, sendet sie die erste Anfrage für die msgsrv.php Datei. Wenn es gelingt, hängen wir die Nachricht an die #messages div, dann rufen wir nach 1 Sekunde die Funktion waitForMsg erneut auf, was die Wartezeit auslöst.

Die 1 Sekunde setTimeout() ist ein wirklich grundlegender Rate-Limiter, es funktioniert ohne, aber wenn msgsrv.php  immer kehrt sofort zurück (zum Beispiel mit einem Syntaxfehler) - Sie überfluten den Browser und es kann schnell einfrieren. Dies sollte besser überprüft werden, wenn die Datei eine gültige JSON-Antwort enthält und / oder eine laufende Gesamtzahl von Anfragen pro Minute / Sekunde hält und entsprechend pausiert.

Wenn die Seite Fehler, hängt es den Fehler an die #messages div, wartet 15 Sekunden und versucht es dann erneut (identisch mit dem, wie wir nach jeder Nachricht 1 Sekunde warten)

Das Schöne an diesem Ansatz ist, dass es sehr belastbar ist. Wenn die Internetverbindung des Clients abbricht, wird ein Zeitlimit überschritten, und dann versuchen Sie es erneut zu verbinden. Dies ist in der Länge der Abfrage enthalten. Es ist keine komplizierte Fehlerbehandlung erforderlich

Wie auch immer, der long_poller.htm Code, mit dem jQuery-Framework:

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

491
2017-12-02 13:15



Ich habe ein wirklich einfaches Chat-Beispiel als Teil von schwappen.

Bearbeiten: (da jeder hier seinen Code einfügt)

Dies ist der komplette JSON-basierte Multi-User-Chat mit Long-Polling und schwappen. Das ist ein Demo wie die Anrufe zu tun, also ignorieren Sie bitte die XSS-Probleme. Niemand sollte dies bereitstellen, ohne es vorher zu bereinigen.

Beachten Sie, dass der Client immer hat eine Verbindung mit dem Server, und sobald jemand eine Nachricht sendet, sollte jeder es 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 <dustin+html@spy.net> -->
<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>

41
2017-12-03 21:08



Tornado ist für Long-Polling gedacht und enthält ein sehr minimales (einige hundert Zeilen Python) Chat-App im /Beispiele / Chatdemo einschließlich Servercode und JS-Clientcode. Es funktioniert so:

  • Clients verwenden JS, um nach Aktualisierungen zu fragen (Anzahl der letzten Nachrichten), der Server URLHandler empfängt diese und fügt einen Rückruf hinzu, um dem Client in einer 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 fragt seit dieser neuen Nachrichten-ID nach Aktualisierungen.


31
2018-03-04 14:53



Ich denke, der Client sieht aus wie eine normale asynchrone AJAX-Anfrage, aber Sie erwarten, dass es eine "lange Zeit" braucht, um wiederzukommen.

Der Server sieht dann so aus.

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

outputNewData();

Also, die AJAX-Anfrage geht zum Server, wahrscheinlich mit einem Zeitstempel des letzten Updates, so dass Ihre hasNewData() weiß, welche Daten du schon hast. Der Server sitzt dann in einer Schleife und schläft, bis neue Daten verfügbar sind. Währenddessen ist Ihre AJAX-Anfrage immer noch verbunden und hängt nur dort auf Daten warten. Wenn neue Daten verfügbar sind, gibt der Server sie schließlich Ihrer AJAX-Anfrage und schließt die Verbindung.


24
2017-12-02 11:39



Hier sind einige Klassen, die ich für Long-Polling in C # verwende. Es gibt grundsätzlich 6 Klassen (siehe unten).

  1. Regler: Verarbeitet Aktionen, die zum Erstellen einer gültigen Antwort (db-Vorgänge usw.) erforderlich sind.
  2. Prozessor: Verwaltet asynch Kommunikation mit der Webseite (selbst)
  3. IAsynchProzessor: Der Dienst verarbeitet Instanzen, die diese Schnittstelle implementieren
  4. Service: Prozesse fordern Objekte an, die IAsynchProcessor implementieren
  5. Anfordern: Der IAsynchProcessor-Wrapper, der Ihre Antwort (Objekt) enthält
  6. Antwort: Enthält benutzerdefinierte Objekte oder Felder

17
2017-09-01 14:20



Dies ist ein netter 5-minütiger Screencast, wie lange mit PHP & jQuery abgefragt werden kann: http://screenr.com/SNH

Code ist dem sehr ähnlich dbrBeispiel oben.


16
2017-10-20 15:41



Hier ist ein einfaches Long-Polling-Beispiel in PHP von Erik Dubbelboer Verwendung der Content-type: multipart/x-mixed-replace Header:

<?

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


12
2017-12-08 12:23



ich benutzte Dies Um mich mit Comet vertraut zu machen, habe ich auch Comet mit dem Java Glassfish Server eingerichtet und viele weitere Beispiele gefunden, indem ich cometdaily.com abonniert habe


11
2017-12-02 11:21