Frage

Ich kann viele Informationen darüber, wie lange Polling Arbeiten (zum Beispiel finden, diese und diese ), aber keine einfach Beispiele, wie dies in Code zu implementieren.

Alles, was ich finden kann, ist cometd , die auf dem Dojo JS Rahmen beruht, und ein ziemlich komplexes Server-System ..

Im Grunde genommen wie würde ich Apache verwenden, um die Anforderungen zu bedienen, und wie würde ich schreiben, ein einfaches Skript (sagen wir, in PHP), das würde „long-Umfrage“ der Server nach neuen Nachrichten?

Das Beispiel nicht skalierbar, sicher und vollständig sein muss, es muss nur an der Arbeit!

War es hilfreich?

Lösung

Es ist einfacher, als ich dachte zunächst .. Grundsätzlich Sie eine Seite haben, die nichts tut, bis die Daten, die Sie zur Verfügung senden wollen, ist (sagen wir, eine neue Nachricht eintrifft).

Hier ist ein wirklich einfaches Beispiel, das nach 2-10 Sekunden einen einfachen String sendet. 1 in 3 Chance, einen Fehler 404 Rückkehr

(Fehlerbehandlung im kommenden Javascript Beispiel 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: Mit einem realen Ort, das ist wie Apache auf einem normalen Web-Server ausgeführt wird, all „Worker-Threads“ schnell binden und lassen Sie es nicht in der Lage zu anderen Anfragen zu reagieren .. Es gibt Möglichkeiten, dies zu umgehen, aber es ist empfohlen, einen „long-Umfrage-Server“ in so etwas wie Python verdrehten zu schreiben, die auf einem Thread nicht verlassen pro Anfrage. cometD ein populäres ist (die in mehreren Sprachen verfügbar ist), und <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>

Andere Tipps

Ich habe ein wirklich einfaches Chat-Beispiel als Teil schwappt .

Bearbeiten : (da jeder ist in hier ihren Code einfügen)

Dies ist das komplette JSON-basierte Multi-User-Chat mit lang Polling und Schwappen . Dies ist eine Demo , wie die Anrufe zu tun, also bitte die XSS Probleme ignorieren. Niemand sollte diese bereitstellen, ohne es zuerst Hygienisierung.

Beachten Sie, dass der Client immer hat eine Verbindung zu dem Server, und sobald jemand eine Nachricht sendet, jeder sollte es etwa 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>

Tornado für Lang Polling ausgelegt und verfügt über eine sehr minimal (wenige hundert Zeilen Python) Chat-App in / Beispiele / chatdemo , einschließlich Server-Code und JS-Client-Code . Es funktioniert wie folgt:

  • Clients verwendet JS für eine Updates seit (Anzahl der letzten Meldung) zu fragen, Server URLHandler diese und fügt einen Rückruf erhält an den Client in eine Warteschlange zu reagieren.

  • Wenn der Server eine neue Nachricht erhält, die onmessage Ereignis ausgelöst wird, kehrt durch die Rückrufe und sendet die Nachrichten.

  • Die clientseitige JS die Nachricht empfängt, fügt sich die Seite, fragt dann nach Updates, da dieser neuen Message-ID.

Ich denke, der Client wie ein normaler asynchroner AJAX-Request aussieht, aber Sie erwarten, dass es eine „lange Zeit“ nehmen, zurückzukommen.

Der Server sieht dann folgendermaßen aus.

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

outputNewData();

So geht der AJAX-Request an den Server, wahrscheinlich mit einem Zeitstempel, wann es war letzte Aktualisierung, so dass Ihr hasNewData() weiß, welche Daten Sie bereits bekommen haben. Der Server setzt sich dann in einer Schleife Schlaf bis neue Daten verfügbar sind. Während der ganzen Zeit, Ihre AJAX-Request noch angeschlossen ist, nur dort hängen auf Daten warten. Schließlich, wenn neue Daten verfügbar sind, wird der Server es zu Ihrer AJAX-Anforderung gibt und schließt die Verbindung.

hier sind einige Klassen, die ich für lange Polling in C # verwenden. Grundsätzlich gibt es sechs Klassen (siehe unten).

  1. Controller : Prozesse Aktionen eine gültige Antwort erstellen erforderlich (. Db Operationen usw.)
  2. Prozessor : Verwaltet asynch Kommunikation mit der Web-Seite (selbst)
  3. IAsynchProcessor : Der Dienst verarbeitet Instanzen, die diese Schnittstelle
  4. implementieren
  5. Sevice : Prozesse Anfrage Objekte, die IAsynchProcessor
  6. implementieren
  7. Anfrage : Die IAsynchProcessor Wrapper mit Ihrer Antwort (Objekt)
  8. Antwort : Enthält benutzerdefinierte Objekte oder Felder

Dies ist ein schöner 5-minütigen Screencasts, wie lange Polling mit PHP & jQuery zu tun: http://screenr.com/SNH

-Code ist ganz ähnlich wie dbr 's Beispiel oben.

Hier ist ein einfaches Lang Polling Beispiel in PHP von Erik Dubbelboer die Content-type: multipart/x-mixed-replace Header mit:

<?

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

Ich benutzte dieser in den Griff zu bekommen Comet, ich habe auch Comet einrichten mit dem Java-Server Glassfish und fand viele andere Beispiele durch den Abschluss cometdaily.com

Hier finden Sie aktuelle diese Blog-Post , den Code für eine einfache Chat-Anwendung hat in Python / Django / GEVENT .

Im Folgenden finden Sie eine lange Polling Lösung, die ich für Inform8 Web entwickelt haben. Grundsätzlich Sie die Klasse außer Kraft setzen und die loaddata Methode implementieren. Wenn der Wert oder loaddata die Betriebszeiten wieder heraus wird es das Ergebnis ausdrucken und zurück.

Wenn die Verarbeitung des Skripts kann länger als 30 Sekunden dauern, müssen Sie möglicherweise die set_time_limit () aufrufen, um etwas mehr ä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();

}

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

1000 /* ..after 1 seconds */

ich denke, es sollte

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

für sie arbeiten.

Für Interessenten, habe ich versucht, ein Äquivalent Django. Starten Sie ein neues Django-Projekt, sagen lp für Lang-Abfrage:

django-admin.py startproject lp

Rufen Sie die App msgsrv für Message-Server:

python manage.py startapp msgsrv

Fügen Sie die folgenden Zeilen in settings.py haben eine Vorlagen Verzeichnis:

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 wie folgt 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 templates / long_poller.htm sollten die gleichen wie oben mit Tippfehler korrigiert werden. Hoffe, das hilft.

Dies ist eines der Szenarien, die PHP eine sehr schlechte Wahl für ist. Wie bereits erwähnt, können Sie alle Ihre Apache Arbeiter sehr schnell so etwas wie diese binden zu tun. PHP ist für Anfang gebaut, führt, zu stoppen. Es ist nicht für den Start gebaut, wartet ... ausführen, stoppen. Sie werden Ihren Server sehr schnell festfahren und feststellen, dass Sie unglaubliche Skalierung Probleme haben.

Wie gesagt, können Sie immer noch das tun mit PHP und haben es nicht Ihre Server töten die nginx mit HttpPushStreamModule: http: //wiki.nginx.org/HttpPushStreamModule

Sie Setup nginx vor Apache (oder was auch immer), und es wird die Anzahl gleichzeitiger Verbindungen von Offenhalten kümmern. Sie reagieren nur mit Nutzlast von Daten an eine interne Adresse zu senden, die Sie mit einem Hintergrund-Job tun könnten, oder einfach nur die Nachrichten an Menschen abgefeuert, die darauf warten, wann immer die neuen Anforderungen kommen in. Dies hält PHP Prozesse von dem während der langen Wahl offen sitzen.

Dies ist nicht exklusiv für PHP und kann mit nginx mit jeder Backend-Sprache erfolgen. Die gleichzeitige offene Verbindungen Last ist gleich Node.js so der größte Vorteil ist, dass es Sie steigt aus Knoten für so etwas zu brauchen.

Sie sehen eine Menge anderer Leute andere Sprachbibliotheken erwähnen für langes Polling erreichen und das ist mit gutem Grunde. PHP ist gut einfach nicht für diese Art von Verhalten natürlich gebaut.

Warum das Web-Sockets statt langen Polling nicht in Betracht ziehen? Sie sind viel effizienter und einfach zu installieren. Allerdings sind sie nur in modernen Browsern unterstützt. Hier ist eine schnelle Referenz .

Die WS-I-Gruppe etwas namens veröffentlicht "Zuverlässig Sicher Profil" , die eine Glasfische und .NET-Implementierung hat, dass offenbar inter arbeiten gut.

Mit etwas Glück gibt es ein Javascript Implementierung gibt auch.

Es gibt auch eine Silverlight-Implementierung, die HTTP Duplex. können Sie Javascript die Verbindung Silverlight Objekt Rückrufe zu erhalten, wenn ein Stoß auftritt.

Es gibt auch kommerzielle kostenpflichtigen Versionen auch.

Für eine ASP.NET MVC Implementierung sehen SignalR die auf NuGet verfügbar ist .. beachten Sie, dass die NuGet ist oft veraltet aus der Git Quelle , die sehr häufig Commits wird.

Lesen Sie mehr über SignalR auf einem Scott Hanselman Blog auf rel="nofollow">

Sie können versuchen, icomet ( https://github.com/ideawu/icomet ), eine C1000K C ++ Komet Server mit libevent gebaut. icomet bietet auch eine JavaScript-Bibliothek, es einfach ist, so einfach zu bedienen wie

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 breite Palette von Browser und Betriebssysteme, einschließlich Safari (iOS, Mac), IEs (Windows), Firefox, Chrome etc.

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

Produktion weise Szenario in Express für exmaple Sie response in der Middleware erhalten würde. Haben Sie, was Sie tun müssen, können Umfang aus all den langen abgefragten Methoden zur Karte oder etwas (dh sichtbar für andere Strömungen) und <Response> response.end() aufrufen, wenn Sie bereit sind. Es ist nichts Besonderes lange abgefragt Verbindungen. Der Rest ist, wie Sie in der Regel Ihre Anwendung strukturieren.

Wenn Sie nicht wissen, was ich meine von Scoping, das sollten Sie 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, ein, tun, was Sie wollen. Es gibt id für jede Anfrage so sollten Sie in der Lage Karte zu verwenden und spezifischen Zugriff aus api Anruf.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top