Basit "Uzun Yoklama"

18 Cevap php

Ben (Örneğin, this, ve this) nasıl Uzun Yoklama eserleri üzerine pek çok bilgi bulabilirsiniz, ancak bu kodu uygulamak için nasıl bir simple örnekleri .

Ben bulabilirsiniz tüm Dojo JS çerçevesinde ve oldukça karmaşık bir sunucu sistemine dayandığı, cometd olduğunu ..

Temelde, nasıl ben isteklere hizmet için Apache kullanmak istiyorsunuz ve nasıl (PHP diyelim) basit bir senaryo yazmak hangi would "uzun-poll" Yeni iletiler için sunucu?

Örnek, ölçeklenebilir, güvenli ya da tam olması değil, sadece çalışmak gerekiyor!

18 Cevap

Ben başlangıçta düşündüğünüzden daha basittir .. göndermek istediğiniz verileri (örneğin, yeni bir mesaj geldiğinde) hazır olana kadar Temelde, hiçbir şey yapmaz bir sayfa var.

Burada 2-10 saniye sonra basit bir dize gönderir, gerçekten temel bir örnektir. Bir hata dönmeden 1 3 şans 404 (önümüzdeki JavaScript örnekte hata işleme göstermek için)

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

Not: Gerçek bir site ile, Apache gibi normal bir web sunucusu üzerinde çalışan bu hızla tüm "işçi konuları" kravat ve diğer istekleri .. Bu etrafında yolu vardır cevap veremiyoruz bırakın, ama yazmak için önerilir olacak Python en twisted, istek başına bir iş parçacığı üzerinde dayanmaz ki gibi bir şey, bir "uzun anket sunucusu". cometD (birçok dilde mevcuttur) bir popüler olanıdır, ve Tornado (o FriendFeed uzun yoklama kodu için inşa edildi) gibi görevler için özel olarak yapılmış yeni bir çerçeve .. . ama basit bir örnek olarak, Apache yeterli fazla! Bu komut kolayca (çok yaygın olarak Apache / PHP seçti ve ben yerel olarak çalışıyor olması oldu) herhangi bir dilde yazılmış olabilir

Sonra, Javascript, sen (msg_srv.php) Yukarıdaki dosyayı talep ve cevap bekleyin. Eğer bir tane olsun, verilerin üzerine hareket. Sonra dosyayı talep ve tekrar beklemek, veri (ve tekrar) üzerine hareket

Aşağıda sayfa yüklendiğinde, o başarılı olursa, biz {mesajı ekleme .. msgsrv.php dosyası için ilk isteği gönderir .. Böyle bir sayfanın bir örneğidir [(1)] } div, sonra 1 saniye sonra biz beklemek tetikler, yine waitForMsg işlevini çağırın.

1 saniye setTimeout() Bu olmadan çalışıyor, gerçekten temel bir oran-sınırlayıcı, ama msgsrv.php always, örneğin, bir sözdizimi hatası ile (anında dönerse ) - Eğer tarayıcı sel ve hızlı bir şekilde dondurabilirsiniz. Bu, daha iyi dosya geçerli bir JSON yanıt içerip içermediğini kontrol yapılır ve / veya requests-per-minute/second bir çalışan toplam tutmak ve uygun duraklatma olacaktır.

Sayfa hataları varsa, bu #messages div hatayı ekler 15 saniye bekler ve sonra (biz her mesajdan sonra 1 saniye beklemek nasıl aynı) tekrar dener

Bu yaklaşım hakkında güzel bir şey, çok esnek olmasıdır. Müşterilerine internet bağlantısı ölürse, o zaman aşımı sonra denemek ve yeniden - bu nasıl çalıştığını uzun yoklama doğasında vardır, hiçbir karmaşık hata işleme gereklidir

Neyse, jQuery framework kullanarak long_poller.htm kodu:

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

Ben bir parçası olarak bir çok basit bir sohbet örneği var slosh.

Edit: (herkes burada kendi kodu yapıştırarak beri)

Bu uzun yoklama ve slosh kullanarak tam JSON tabanlı çoklu kullanıcı sohbet. Bu demo yüzden XSS sorunları görmezden lütfen aramaları yapmak için nasıl olduğunu. Kimse ilk önce hijyen olmadan bu dağıtmak gerekir.

Istemci always sunucuya bir bağlantı vardır, ve en kısa sürede herkes bir mesaj gönderir gibi, herkes kabaca anında görmek gerektiğini edin.

<?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 uzun yoklama için tasarlanmış, ve sunucu kodu ve JS istemci kodu dahil / çok az (Python birkaç yüz hatları) chat app examples/chatdemo, içerir . Bu gibi çalışır:

  • Müşteriler (son mesajın sayısı) beri güncellemeleri istemek için JS kullanmak, sunucu URLHandler bu alır ve bir sıraya müşteriye cevap bir geri ekler.

  • Sunucu yeni bir mesaj aldığında, onMessage olayı, geri çağrıları aracılığıyla döngüler, ve mesajları gönderir.

  • Istemci tarafı JS, mesajı alır sayfaya ekler, sonra bu yeni mesaj kimliği beri güncellemeleri sorar.

Ben müşteri normal bir asenkron AJAX isteği gibi görünüyor düşünüyorum, ama bunu geri gelmek için bir "uzun zaman" almak için bekliyoruz.

Sunucu daha sonra bu gibi görünüyor.

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

outputNewData();

So, the AJAX request goes to the server, probably including a timestamp of when it was last update so that your hasNewData() knows what data you have already got. The server then sits in a loop sleeping until new data is available. All the while, your AJAX request is still connected, just hanging there waiting for data. Finally, when new data is available, the server gives it to your AJAX request and closes the connection.

This is a nice 5-minute screencast on how to do long polling using PHP & jQuery: http://screenr.com/SNH

Yukarıdaki kod dbr 's örnek oldukça benzer.

İşte a simple long-polling example in PHP by Erik Dubbelboer Content-type: multipart/x-mixed-replace başlığı kullanıyor:

<?

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

Ve burada bir demo:

http://dubbelboer.com/multipart.php

I this Comet ile vâkıf, ben de Java GlassFish sunucusunu kullanarak Comet kurdunuz kullanılan ve cometdaily.com abone tarafından diğer örneklerde birçok bulundu

Kod için teşekkürler, dbr. Çizgisi etrafında * long_poller.htm * sadece küçük bir yazım hatası

1000 /* ..after 1 seconds */

Ben olması gerektiğini düşünüyorum

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

o iş için.

İlgilenenler için, Django eşdeğer çalıştı. Yeni bir Django projesi başlatın, uzun yoklama için lp söylüyor:

django-admin.py startproject lp

App mesaj sunucusu için msgsrv Çağrı:

python manage.py startapp msgsrv

settings.py bir templates dizini için aşağıdaki satırları ekleyin:

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

Gibi urls.py sizin URL desenleri tanımlamak:

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

Ve msgsrv / views.py gibi görünmelidir:

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

Son olarak, templates / * long_poller.htm * yazım hatası düzeltilmiş ile yukarıdaki ile aynı olmalıdır. Umarım bu yardımcı olur.

Python / Django / gevent basit bir sohbet uygulaması için kodu vardır this blog post bir göz atın.

Aşağıda Inform8 Web için geliştirilmiş bir uzun yoklama çözümdür. Temelde sınıf geçersiz ve loaddata yöntemi uygulamak. Loaddata dışarı bir değer veya işlem kez döndüğünde sonucu yazdırmak ve dönecektir.

Senaryonuzun işlem 30 saniyeden daha uzun sürebilir eğer () daha uzun bir şey için çağrı set_time_limit değiştirmek gerekebilir.

Apache 2.0 license. Latest version on 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();

}

Kendiniz uzun yoklama işlemek istemiyorsanız. Bu tür (I) kurulan EZComet olarak bulut hizmetlerini kullanmak için düşünebilirsiniz, burada PHP bir sohbet odası örnek

chatroom demo

Kullanımı çok kolay, yapmanız gereken bütün bir API anahtarı kaydetmek ve almak için, daha sonra PHP kodu mesaj itmek için kullanabilirsiniz

$username = $_POST['username'];
$message = $_POST['message'];
$msg = array(
    'username' => $username,
    'message' => $message
);

$tick = push_msg('your api key', 'demo', 'chatroom', @json_encode($msg));
echo "tick: $tick";

Sonra sayfasında abone

ez_comet.subscribe({
    user_name: 'demo', 
    channel: 'chatroom', 
    callback: callback,
    auto_tick: false,
    msg_type: 'json'
});

WS-I grubu bir cam balık var "Reliable Secure Profile" denilen bir şey yayınlandı ve .NET implementation görünüşe inter-operate iyi.

Herhangi bir şans ile bir Javascript Orada uygulaması da var.

Bir itme oluştuğunda HTTP Duplex. Sen connect javascript to the Silverlight nesne geri çağrıları almak için kullanan bir Silverlight uygulaması da vardır.

Orada da vardır commercial paid versions de.

Here is a node.js example bir jquery istemcisi ile birlikte geliyor. Heroku üzerine kurma hakkında talimatlar da var.

Bir ASP.NET MVC uygulama için, which is available on NuGet .. NuGet Git source çok sık kaydedilmesini alır tarihe sık sık dışarı olduğuna dikkat SignalR bak.

Bir blog on by Scott Hanselman üzerine SignalR hakkında daha fazla okuyun

Sen icomet deneyebilirsiniz (https://github.com/ideawu/icomet), Libevent ile inşa C1000K C + + kuyrukluyıldız sunucu. icomet aynı zamanda gibi basit kullanımı kolay bir JavaScript kütüphanesi sağlar

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 geniş bir yelpazede destekler Tarayıcılar vb Safari (iOS, Mac), IE'lerin (Windows), Firefox, Chrome, işletim sistemleri de dahil olmak üzere,

Neden bunun yerine uzun yoklama web soketleri düşünmüyorsunuz? Onlar çok verimli ve kurulumu kolay. Ancak onlar sadece modern tarayıcılarda desteklenir. İşte quick reference .

Bu PHP için çok kötü bir seçimdir senaryolardan biridir. Daha önce de belirtildiği gibi, Apache işçilerin hepsi çok hızlı bir şekilde böyle bir şey yaptığını bağlayabilir. PHP durdurmak, yürütmek, başlangıç ​​için inşa edilmiştir. Durdurmak, yürütmek bekleyin ... Bu, başlangıç ​​için inşa değil. Çok hızlı bir şekilde sunucu çıkmaza ve inanılmaz ölçeklendirme sorunları var olduğunu göreceksiniz.

O dedi, sen hala PHP ile yapabilirsiniz ve nginx HttpPushStreamModule kullanarak sunucu öldürmek değil: http://wiki.nginx.org/HttpPushStreamModule

Apache (ya da başka ne olursa olsun) önünde kurulum nginx ve eşzamanlı bağlantıları açık tutarak ilgilenir. Sen sadece bir arka plan iş yapmak ya da sadece mesaj bu uzun yoklama sırasında açık oturma PHP süreçlerini tutar içeri yeni istekler gelip zaman bekliyorlardı insanlara kapalı kovdurabilirdim dahili adres veri göndererek yükü ile yanıt verir.

Bu PHP için özel değildir ve herhangi bir arka uç dil ile nginx kullanılarak yapılabilir. Eşzamanlı açık bağlantıları yükü öylesine büyük dikmek o böyle bir şey için Düğümü GEREK dışarı alır olduğunu node.js eşittir.

Uzun yoklama gerçekleştirmek için başka bir dil libraries söz başka bir sürü insan görmek ve iyi bir nedeni var. PHP sadece iyi doğal davranış bu tür için inşa değildir.