Wie implementiere ich grundlegendes „Long Polling“?

Lesezeit: 11 Minuten

Wie implementiere ich grundlegendes „Long Polling
dbr

Ich kann viele Informationen darüber finden, wie Long Polling funktioniert (z. B. Dasund Das), aber nein einfach Beispiele dafür, wie dies im Code implementiert wird.

Alles, was ich finden kann, ist Kometdas auf dem Dojo JS-Framework basiert, und einem ziemlich komplexen Serversystem.

Wie würde ich im Grunde Apache verwenden, um die Anforderungen zu bedienen, und wie würde ich ein einfaches Skript schreiben (z. B. in PHP), das den Server nach neuen Nachrichten “lang abfragt”?

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

Wie implementiere ich grundlegendes „Long Polling
dbr

Es ist einfacher, als ich anfangs dachte. Im Grunde haben Sie eine Seite, die nichts tut, bis die Daten, die Sie senden möchten, verfügbar sind (sagen wir, eine neue Nachricht kommt).

Hier ist ein wirklich einfaches Beispiel, das nach 2-10 Sekunden einen einfachen String sendet. Wahrscheinlichkeit von 1 zu 3, 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 eine echte Site auf einem normalen Webserver wie Apache ausführen, werden schnell alle “Worker-Threads” blockiert und sie kann nicht auf andere Anfragen reagieren. Es gibt Möglichkeiten, dies zu umgehen, aber es wird empfohlen, zu schreiben ein “Long-Poll-Server” in etwas wie dem von Python verdrehtedie nicht auf einen Thread pro Anfrage angewiesen ist. KometD ist ein beliebtes (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 den Long-Polling-Code von FriendFeed entwickelt) … aber als einfaches Beispiel ist Apache mehr als ausreichend! Dieses Skript könnte leicht in jeder Sprache geschrieben werden (ich habe Apache/PHP gewählt, da sie sehr verbreitet sind und ich sie zufällig lokal ausgeführt habe).

Dann fordern Sie in Javascript die obige Datei an (msg_srv.php) und auf eine Antwort warten. Wenn Sie eine erhalten, handeln Sie anhand der Daten. Dann fordern Sie die Datei an und warten erneut, handeln nach den Daten (und wiederholen)

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

Die 1 Sekunde setTimeout() ist ein wirklich einfacher Ratenbegrenzer, es funktioniert gut ohne diesen, aber wenn msgsrv.php immer kehrt sofort zurück (z. B. mit einem Syntaxfehler) – Sie überfluten den Browser und er kann schnell einfrieren. Dies sollte besser durchgeführt werden, indem überprüft wird, ob die Datei eine gültige JSON-Antwort enthält, und/oder eine laufende Summe der Anforderungen pro Minute/Sekunde beibehalten und entsprechend angehalten wird.

Wenn die Seite fehlerhaft ist, wird der Fehler an die angehängt #messages div, wartet 15 Sekunden und versucht es dann erneut (identisch wie wir 1 Sekunde nach jeder Nachricht warten)

Das Schöne an diesem Ansatz ist, dass er sehr belastbar ist. Wenn die Internetverbindung des Clients unterbrochen wird, kommt es zu einer Zeitüberschreitung. Versuchen Sie dann, die Verbindung erneut herzustellen – dies hängt davon ab, wie lange die Abfrage funktioniert, es ist keine komplizierte Fehlerbehandlung erforderlich

Jedenfalls die long_poller.htm Code unter Verwendung des jQuery-Frameworks:

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

  • Könnten nicht einige Nachrichten mit dieser Idee durchschlüpfen? In diesem 1-Sekunden-Timeout wurden beispielsweise 1000 Chat-Nachrichten gesendet, woher sollte der Server wissen, dass er die 1000 Nachrichten speziell an diesen Client senden soll?

    – DevDevDev

    7. Oktober 2009 um 3:36 Uhr

  • 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 diese 1000 Nachrichten für diesen bestimmten Client gespeichert und in einem Stück gesendet werden. Sie können das WaitForMsg-Timeout auch sicher reduzieren

    – dbr

    7. Oktober 2009 um 13:32 Uhr

  • nodejs ist eine weitere ausgezeichnete serverseitige Lösung für lange Polling-Anfragen, mit dem zusätzlichen Vorteil (gegenüber Twisted), dass Sie Servercode auch in Javascript schreiben können.

    – Husky

    25. Februar 2011 um 19:10 Uhr

  • Dies ist nur eine einfache wiederkehrende AJAX-Verbindung zum Server mit einem Intervall von 1 Sekunde. Das hat nichts mit „langem Polling“ zu tun. Lange Abfragen sollten die Verbindung aufrechterhalten, solange ein Client-Timeout auftritt.

    – Dele

    5. Mai 2011 um 12:46 Uhr

  • Die Frage ist, was macht ein echtes PHP-Skript stattdessen sleep(rand(2,10)); ? um nichts zu tun, die Datenbank alle 100 Millisekunden abfragen? Wann beschließt es zu sterben?

    – Luis Siquot

    28. September 2011 um 3:29 Uhr

1647081250 486 Wie implementiere ich grundlegendes „Long Polling
Dustin

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

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

Dies ist der vollständige JSON-basierte Multi-User-Chat mit Long-Polling und schwappen. Das ist ein Demo wie die Aufrufe durchzuführen sind, also ignorieren Sie bitte die XSS-Probleme. Niemand sollte dies bereitstellen, ohne es vorher zu desinfizieren.

Beachten Sie, dass der Client immer hat eine Verbindung zum Server, und 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>

  • Darf ich wissen, wie das immer zusammenhängt? Entschuldigung, wenn ich etwas Dummes frage, aber das will ich wissen.

    – Rocky Singh

    22. Januar 2011 um 23:31 Uhr

  • 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 alles andere in eine Warteschlange, und der Client stellt dann die Verbindung wieder her und nimmt die fehlenden Nachrichten auf, falls vorhanden, andernfalls blockiert er erneut.

    – Dustin

    22. Januar 2011 um 23:46 Uhr

  • Mag zunächst nicht offensichtlich sein, aber die Sache ist die, die für den „immer verbundenen Zustand“ verantwortlich ist ajaxStop mit getNewComments Rückruf dort, also wird es einfach endlos am Ende jeder Ajax-Anfrage ausgelöst

    – Glatzen

    20. Januar 2016 um 16:41 Uhr


1647081250 570 Wie implementiere ich grundlegendes „Long Polling
mikemaccana

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

  • Clients verwenden JS, um nach Aktualisierungen seit (Nummer der letzten Nachricht) zu fragen, 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.

  • Das clientseitige JS empfängt die Nachricht, fügt sie der Seite hinzu und fragt dann nach Aktualisierungen seit dieser neuen Nachrichten-ID.

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-Anfrage geht also an den Server, wahrscheinlich einschließlich eines Zeitstempels der letzten Aktualisierung, damit Ihre hasNewData() weiß, welche Daten Sie bereits haben. Der Server befindet sich dann in einer Schleife und schläft, bis neue Daten verfügbar sind. Währenddessen ist Ihre AJAX-Anfrage immer noch verbunden und wartet nur auf Daten. Wenn schließlich neue Daten verfügbar sind, gibt der Server diese an Ihre AJAX-Anfrage weiter und schließt die Verbindung.

1647081250 625 Wie implementiere ich grundlegendes „Long Polling
Gefangener NULL

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 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. Dienst: Verarbeitet Anforderungsobjekte, die IAsynchProcessor implementieren
  5. Anfrage: Der IAsynchProcessor-Wrapper, der Ihre Antwort enthält (Objekt)
  6. Antwort: Enthält benutzerdefinierte Objekte oder Felder

  • Okay … also WARUM wurde das abgelehnt? Diese Klassen sind in der Tat gültige Beispiele für Long-Polling.

    – Gefangener NULL

    28. September 2011 um 17:36 Uhr

  • Echtes Long-Polling ist nicht (einfach) die Praxis, das Intervall zu erhöhen, in dem Sie eine normale Abfrage (für eine Ressource) durchführen. Es ist Teil eines größeren Musters … das “etwas” der Interpretation unterliegt … aber nur in bestimmten Bereichen der Gesamtimplementierung. Das heißt … diese Klassen folgen dem Muster! Wenn Sie also einen Grund haben, dies abzulehnen … würde mich wirklich der Grund interessieren.

    – Gefangener NULL

    12. Juni 2012 um 19:05 Uhr


  • Vielleicht wurde es abgelehnt, da es die Frage nach einem einfachen Codebeispiel nicht direkt anspricht. Natürlich habe ich es nicht abgelehnt, also kann ich nur raten.

    – Andreas

    15. Juni 2012 um 15:22 Uhr

Wie implementiere ich grundlegendes „Long Polling
Sean O

Dies ist ein netter 5-minütiger Screencast darüber, wie man lange Abfragen mit PHP und jQuery durchführt:
http://screenr.com/SNH

Code ist ziemlich ähnlich zu dbrBeispiel oben.

  • Okay … also WARUM wurde das abgelehnt? Diese Klassen sind in der Tat gültige Beispiele für Long-Polling.

    – Gefangener NULL

    28. September 2011 um 17:36 Uhr

  • Echtes Long-Polling ist nicht (einfach) die Praxis, das Intervall zu erhöhen, in dem Sie eine normale Abfrage (für eine Ressource) durchführen. Es ist Teil eines größeren Musters … das “etwas” der Interpretation unterliegt … aber nur in bestimmten Bereichen der Gesamtimplementierung. Das heißt … diese Klassen folgen dem Muster! Wenn Sie also einen Grund haben, dies abzulehnen … würde mich wirklich der Grund interessieren.

    – Gefangener NULL

    12. Juni 2012 um 19:05 Uhr


  • Vielleicht wurde es abgelehnt, da es die Frage nach einem einfachen Codebeispiel nicht direkt anspricht. Natürlich habe ich es nicht abgelehnt, also kann ich nur raten.

    – Andreas

    15. Juni 2012 um 15:22 Uhr

Wie implementiere ich grundlegendes „Long Polling
dbr

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

993390cookie-checkWie implementiere ich grundlegendes „Long Polling“?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy