ฉันจะใช้“ Long Polling” พื้นฐานได้อย่างไร


776

ฉันสามารถค้นหาข้อมูลจำนวนมากเกี่ยวกับวิธีการทำงานของ Long Polling (ตัวอย่างเช่นสิ่งนี้และสิ่งนี้ ) แต่ไม่มีตัวอย่างง่ายๆของวิธีการใช้สิ่งนี้ในโค้ด

ทั้งหมดที่ฉันสามารถหาได้คือcometdซึ่งอาศัยเฟรมเวิร์ก Dojo JS และระบบเซิร์ฟเวอร์ที่ค่อนข้างซับซ้อน ..

โดยทั่วไปแล้วฉันจะใช้ Apache เพื่อตอบสนองการร้องขอได้อย่างไรและฉันจะเขียนสคริปต์อย่างง่าย ๆ (เช่นใน PHP) ซึ่งจะ "สำรวจความยาว" เซิร์ฟเวอร์สำหรับข้อความใหม่ได้อย่างไร

ตัวอย่างไม่จำเป็นต้องปรับขนาดได้ปลอดภัยหรือสมบูรณ์เพียงแค่ต้องทำงาน!

คำตอบ:


512

มันง่ายกว่าที่ฉันคิดไว้ในตอนแรก .. โดยทั่วไปคุณมีหน้าเว็บที่ไม่ทำอะไรเลยจนกว่าจะมีข้อมูลที่คุณต้องการส่ง (พูดว่ามีข้อความใหม่มาถึง)

นี่คือตัวอย่างพื้นฐานจริง ๆ ซึ่งส่งสตริงง่าย ๆ หลังจาก 2-10 วินาที โอกาส 1 ใน 3 ในการส่งคืนข้อผิดพลาด 404 (เพื่อแสดงการจัดการข้อผิดพลาดในตัวอย่าง Javascript ที่กำลังมา)

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

หมายเหตุ: ด้วยไซต์จริงการเรียกใช้สิ่งนี้บนเว็บเซิร์ฟเวอร์ปกติเช่น Apache จะผูก "กระทู้ผู้ทำงาน" ทั้งหมดอย่างรวดเร็วและปล่อยให้มันไม่สามารถตอบสนองต่อคำขออื่น ๆ ได้ .. มีวิธีแก้ไขปัญหานี้อยู่แล้ว แต่ขอแนะนำให้เขียน "เซิร์ฟเวอร์แบบสำรวจความคิดเห็นยาว" ในสิ่งที่คล้ายกับ Python twistedซึ่งไม่ขึ้นอยู่กับหนึ่งเธรดต่อคำขอ cometDเป็นหนึ่งที่ได้รับความนิยม (ซึ่งมีให้บริการในหลายภาษา) และTornadoเป็นเฟรมเวิร์กใหม่ที่สร้างขึ้นเป็นพิเศษสำหรับงานดังกล่าว (มันถูกสร้างขึ้นสำหรับรหัสโพลแบบยาวของ FriendFeed) ... แต่เป็นตัวอย่างง่ายๆ Apache ก็เพียงพอแล้ว ! สคริปต์นี้สามารถเขียนได้อย่างง่ายดายในทุกภาษา (ฉันเลือก Apache / PHP เนื่องจากเป็นเรื่องธรรมดามากและฉันก็เรียกใช้พวกเขาในพื้นที่)

จากนั้นใน Javascript คุณขอไฟล์ด้านบน ( msg_srv.php) และรอการตอบกลับ เมื่อคุณได้รับหนึ่งคุณดำเนินการกับข้อมูล จากนั้นคุณร้องขอไฟล์และรออีกครั้งดำเนินการกับข้อมูล (และทำซ้ำ)

สิ่งต่อไปนี้เป็นตัวอย่างของหน้าดังกล่าว .. เมื่อหน้าโหลดมันจะส่งคำขอเริ่มต้นสำหรับmsgsrv.phpไฟล์ .. ถ้ามันประสบความสำเร็จเราผนวกข้อความไปยัง#messagesdiv แล้วหลังจาก 1 วินาทีที่เราเรียกใช้ฟังก์ชั่น waitForMsg อีกครั้ง ซึ่งก่อให้เกิดการรอคอย

1 ที่สองsetTimeout()เป็นอัตราที่ limiter พื้นฐานจริงๆก็ทำงานได้ดีโดยไม่ต้องนี้ แต่ถ้าmsgsrv.php เสมอจะส่งกลับทันที (ที่มีข้อผิดพลาดทางไวยากรณ์เช่น) - คุณน้ำท่วมเบราว์เซอร์และมันได้อย่างรวดเร็วสามารถแข็งขึ้น สิ่งนี้จะเป็นการดีกว่าถ้าตรวจสอบว่าไฟล์มีการตอบสนอง JSON ที่ถูกต้องและ / หรือรักษาคำขอรวมต่อนาที / วินาทีที่กำลังทำงานอยู่ทั้งหมดและหยุดชั่วคราวอย่างเหมาะสม

หากหน้าผิดพลาดมันจะผนวกข้อผิดพลาดกับ#messagesdiv รอ 15 วินาทีจากนั้นลองอีกครั้ง (เหมือนกับที่เรารอ 1 วินาทีหลังจากแต่ละข้อความ)

ข้อดีของวิธีนี้คือมีความยืดหยุ่น หากการเชื่อมต่ออินเทอร์เน็ตของลูกค้าตายก็จะหมดเวลาจากนั้นลองเชื่อมต่อใหม่ - สิ่งนี้มีอยู่ในการทำงานของหน่วยเลือกตั้งนานไม่ต้องจัดการข้อผิดพลาดที่ซับซ้อน

อย่างไรก็ตามlong_poller.htmรหัสโดยใช้กรอบ jQuery:

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

7
ข้อความบางส่วนไม่สามารถส่งผ่านความคิดนี้ได้ใช่ไหม ในการหมดเวลา 1 วินาทีบอกว่ามีการส่งข้อความแชท 1,000 ข้อความเซิร์ฟเวอร์จะทราบได้อย่างไรว่าจะส่งข้อความ 1,000 รายการไปยังไคลเอ็นต์นั้นโดยเฉพาะ
DevDevDev

15
อาจ. นี่เป็นตัวอย่างที่ง่ายมากในการสาธิตแนวคิด .. ในการทำสิ่งนี้ให้ดีขึ้นคุณจะต้องใช้โค้ดฝั่งเซิร์ฟเวอร์ที่ซับซ้อนยิ่งขึ้นซึ่งมันจะเก็บข้อความ 1,000 ข้อความเหล่านั้นไว้สำหรับไคลเอนต์นั้นและส่งพวกมันเป็นก้อน คุณสามารถลดการหมดเวลาของ waitForMsg ได้อย่างปลอดภัย
dbr

21
nodejsเป็นอีกหนึ่งโซลูชั่นด้านเซิร์ฟเวอร์ที่ยอดเยี่ยมสำหรับคำขอการทำโพลแบบยาวโดยมีข้อได้เปรียบเพิ่มเติม (มากกว่า Twisted) ที่คุณสามารถเขียนรหัสเซิร์ฟเวอร์ใน Javascript ได้เช่นกัน
ฮัสกี้

8
นี่เป็นเพียงการเชื่อมต่อ AJAX ธรรมดาที่เกิดซ้ำกับเซิร์ฟเวอร์ที่มีช่วงเวลา 1 วินาที สิ่งนี้ไม่เกี่ยวข้องกับ "การทำโพลแบบยาว" การทำโพลแบบยาวควรให้การเชื่อมต่อมีชีวิตอยู่ตราบใดที่ลูกค้าหมดเวลา
Deele

6
คำถามคือสิ่งที่สคริปต์ PHP จริงทำแทนsleep(rand(2,10));อะไร เพื่อที่จะไม่ทำอะไรเลยสำรวจฐานข้อมูลละ 100 milisecs เมื่อไหร่จะตัดสินใจตาย
Luis Siquot

41

ฉันมีตัวอย่างเช่นการแชทง่ายจริงๆเป็นส่วนหนึ่งของโคลน

แก้ไข : (เนื่องจากทุกคนวางโค้ดไว้ที่นี่)

นี่คือการแชทแบบหลายผู้ใช้แบบ JSON ที่สมบูรณ์โดยใช้การทำโพลและslosh แบบยาว นี่เป็นตัวอย่างของวิธีการโทรดังนั้นโปรดข้ามปัญหา XSS ไม่มีใครควรปรับใช้สิ่งนี้โดยไม่ทำให้ถูกสุขลักษณะก่อน

ขอให้สังเกตว่าลูกค้ามักจะมีการเชื่อมต่อไปยังเซิร์ฟเวอร์และเร็วที่สุดเท่าที่ทุกคนที่ส่งข้อความไปทุกคนควรเห็นมันประมาณทันที

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

1
ฉันขอทราบได้ไหมว่าสิ่งนี้เชื่อมโยงกันอยู่เสมอ? ขออภัยถ้าฉันถามอะไรโง่ ๆ แต่ฉันอยากรู้
Rocky Singh

4
มันเป็น HTTP GET และเซิร์ฟเวอร์บล็อก GET จนกว่าจะมีข้อมูลพร้อมใช้งาน เมื่อข้อมูลมาถึงเซิร์ฟเวอร์เซิร์ฟเวอร์จะส่งคืนข้อมูลไปยังไคลเอนต์เข้าคิวสิ่งอื่น ๆ ที่อาจเข้ามาจากนั้นลูกค้าจะเชื่อมต่อและรับข้อความที่หายไปถ้ามีมิฉะนั้นจะบล็อกอีกครั้ง
ดัสติ

4
อาจไม่ชัดเจนในตอนแรก แต่สิ่งที่รับผิดชอบสำหรับ 'สถานะที่เชื่อมต่อเสมอ' คือajaxStopด้วยการgetNewCommentsเรียกกลับที่นั่นดังนั้นมันจึงทำการยิงเมื่อสิ้นสุดของคำขอ
อาแจ็กซ์

32

Tornadoได้รับการออกแบบมาเพื่อการสำรวจระยะยาวและมีแอพแชท Python ที่น้อยมาก (ไม่กี่ร้อยบรรทัด) ใน/ samples / chatdemoรวมถึงรหัสเซิร์ฟเวอร์และรหัสลูกค้า JS มันได้ผลเช่นนี้:

  • ลูกค้าใช้ JS เพื่อขออัปเดตตั้งแต่ (จำนวนข้อความล่าสุด) เซิร์ฟเวอร์ URLHandler ได้รับสิ่งเหล่านี้และเพิ่มการโทรกลับเพื่อตอบสนองต่อลูกค้าไปยังคิว

  • เมื่อเซิร์ฟเวอร์ได้รับข้อความใหม่เหตุการณ์ onmessage จะยิงวนรอบการเรียกกลับและส่งข้อความ

  • JS ฝั่งไคลเอ็นต์ได้รับข้อความเพิ่มไปยังหน้าจากนั้นขอการปรับปรุงตั้งแต่ ID ข้อความใหม่นี้


25

ฉันคิดว่าไคลเอนต์ดูเหมือนคำขอ AJAX แบบอะซิงโครนัสปกติ แต่คุณคาดว่าจะใช้เวลา "นาน" ในการกลับมา

เซิร์ฟเวอร์จะมีลักษณะเช่นนี้

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

outputNewData();

ดังนั้นคำขอ AJAX จะไปที่เซิร์ฟเวอร์ซึ่งอาจรวมถึงการประทับเวลาของเมื่อมีการอัปเดตครั้งล่าสุดเพื่อที่คุณจะได้hasNewData()ทราบว่ามีข้อมูลใดบ้าง จากนั้นเซิร์ฟเวอร์จะอยู่ในโหมดวนรอบจนกว่าจะมีข้อมูลใหม่ ในขณะที่คำขอ AJAX ของคุณยังคงเชื่อมต่ออยู่แค่รอข้อมูลอยู่ ในที่สุดเมื่อมีข้อมูลใหม่เซิร์ฟเวอร์จะให้ข้อมูลกับคำขอ AJAX ของคุณและปิดการเชื่อมต่อ


10
นี่คือการรอไม่ว่างที่บล็อกเธรดปัจจุบันของคุณ ไม่ได้ปรับขนาดเลย
Wouter Lievens

10
ไม่ usleep ไม่ใช่การรอที่ยุ่ง และจุดรวมของ "การรอ" คือการบล็อกเธรดของคุณชั่วขณะหนึ่ง บางทีเขาอาจหมายถึง 50 มิลลิวินาที (usleep (50,000)) แต่ไม่ใช่ 50 microseconds! แต่อย่างไรก็ตามด้วยการติดตั้ง Apache / PHP ทั่วไปมีวิธีอื่นในการทำเช่นนี้หรือไม่?
Matt

จากหลักการเบื้องต้นคุณไม่สามารถสร้างฟังก์ชั่นการบล็อกสำหรับข้อความแชทได้โดยไม่ต้องรอ
Tomáš Zato - Reinstate Monica

ยอดเยี่ยมจริง ๆ ! ฉันสร้างฟังก์ชั่นวนซ้ำในเซิร์ฟเวอร์เพื่อตรวจสอบข้อมูลใหม่ แต่ผลิตภัณฑ์ที่ดีที่สุดในการใช้โพลที่มีประสิทธิภาพคืออะไร ฉันใช้ Apache ปกติและเซิร์ฟเวอร์ไม่ตอบสนองเมื่อฉันเปิดแท็บเบราว์เซอร์มากกว่า 4/5 ครั้ง :( มองหาบางอย่างที่จะใช้กับ PHP
moderns

17

นี่คือบางคลาสที่ฉันใช้สำหรับการโพลแบบยาวใน C # โดยทั่วไปมี 6 คลาส (ดูด้านล่าง)

  1. ตัวควบคุม : กระบวนการที่ต้องดำเนินการเพื่อสร้างการตอบสนองที่ถูกต้อง (การดำเนินงาน db และอื่น ๆ )
  2. หน่วยประมวลผล : จัดการการสื่อสารแบบ Asynch กับหน้าเว็บ (ตัวเอง)
  3. IAsynchProcessor : บริการประมวลผลอินสแตนซ์ที่ใช้อินเทอร์เฟซนี้
  4. บริการ : กระบวนการร้องขอวัตถุที่ใช้ IAsynchProcessor
  5. คำขอ : wrapper IAsynchProcessor ที่มีการตอบสนองของคุณ (วัตถุ)
  6. การตอบสนอง : มีวัตถุหรือฟิลด์ที่กำหนดเอง

2
โอเค ... ทำไมนี่ถึงถูกโหวต? คลาสเหล่านี้เป็นตัวอย่างที่ถูกต้องของการทำโพลแบบยาว
ศูนย์นักโทษ

การทำโพลแบบยาวนั้นไม่ได้เป็นเพียงแค่การเพิ่มช่วงเวลาที่คุณทำแบบสำรวจความคิดเห็นปกติ (บนทรัพยากร) มันเป็นส่วนหนึ่งของรูปแบบที่ใหญ่กว่า ... ซึ่ง "ค่อนข้าง" อาจมีการตีความ ... แต่เฉพาะในบางพื้นที่ของการใช้งานโดยรวม ที่กล่าวว่า ... ชั้นเรียนเหล่านี้ปฏิบัติตามรูปแบบที่กล่าวไว้! ดังนั้นหากคุณมีเหตุผลในการลงคะแนนในครั้งนี้ ... ฉันจะสนใจในเหตุผลนั้นจริงๆ
Prisoner ZERO

บางทีมันอาจถูกโหวตเนื่องจากไม่ได้ตอบคำถามตัวอย่างง่ายๆของรหัสโดยตรง แน่นอนฉันไม่ได้ลงคะแนนดังนั้นฉันจึงเดาได้เท่านั้น
Andrew

16

นี่คือหน้าจอ 5 นาทีที่ดีสำหรับวิธีการทำโพลแบบยาวโดยใช้ PHP & jQuery: http://screenr.com/SNH

รหัสค่อนข้างคล้ายกับตัวอย่างของdbrด้านบน


3
ฉันคิดว่าคุณควรเห็นสิ่งนี้เป็นข้อมูลเบื้องต้นเกี่ยวกับการทำโพลแบบยาวเพราะการใช้งานนี้จะทำให้เซิร์ฟเวอร์ของคุณใช้งานได้พร้อมกันหลายคน
อัลเฟรด

ฉันแค่เรียนรู้เกี่ยวกับสิ่งเหล่านี้ ... มันเชื่อถือได้หรือไม่มีผู้ใช้เพียงไม่กี่คน ...
somdow

12

นี่เป็นตัวอย่างการโพลแบบยาวอย่างง่ายใน PHP โดย Erik Dubbelboerโดยใช้Content-type: multipart/x-mixed-replaceส่วนหัว:

<?

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

และนี่คือตัวอย่าง:

http://dubbelboer.com/multipart.php


11

ฉันใช้สิ่งนี้เพื่อจับกับ Comet ฉันได้ตั้งค่า Comet โดยใช้เซิร์ฟเวอร์ Java Glassfish และพบตัวอย่างอื่น ๆ มากมายโดยสมัครเป็นสมาชิก cometdaily.com



9

ด้านล่างนี้เป็นวิธีการสำรวจที่มีความยาวที่ฉันพัฒนาขึ้นสำหรับเว็บ Inform8 โดยทั่วไปคุณจะแทนที่คลาสและใช้เมธอด loadData เมื่อ loadData ส่งคืนค่าหรือการดำเนินการหมดเวลาระบบจะพิมพ์ผลลัพธ์และส่งคืน

หากการประมวลผลสคริปต์ของคุณอาจใช้เวลานานกว่า 30 วินาทีคุณอาจต้องเปลี่ยนการเรียก set_time_limit () เป็นบางสิ่งนานกว่านั้น

Apache 2.0 ลิขสิทธิ์ รุ่นล่าสุดบน github https://github.com/ryanhend/Inform8/blob/master/Inform8-web/src/config/lib/Inform8/longpoll/LongPoller.php

ไรอัน

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

}

8

ขอบคุณสำหรับรหัสDBR เพียงพิมพ์เล็กในlong_poller.htmรอบบรรทัด

1000 /* ..after 1 seconds */

ฉันคิดว่ามันควรจะเป็น

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

เพื่อให้มันทำงาน

สำหรับผู้ที่สนใจฉันลอง Django เทียบเท่า เริ่มโครงการ Django ใหม่พูดlpสำหรับการสำรวจแบบยาว:

django-admin.py startproject lp

โทรหาแอปmsgsrvสำหรับเซิร์ฟเวอร์ข้อความ:

python manage.py startapp msgsrv

เพิ่มบรรทัดต่อไปนี้ในsettings.pyเพื่อให้มีไดเรกทอรีเทมเพลต :

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

กำหนดรูปแบบ URL ของคุณในurls.pyเช่น:

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

และ msgsrv / views.pyควรมีลักษณะดังนี้:

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

สุดท้ายเท็มเพลต / long_poller.htmควรตรงกับด้านบนที่มีการแก้ไขการพิมพ์ผิด หวังว่านี่จะช่วยได้


ที่จริงแล้ว"15000"เป็นข้อผิดพลาดทางไวยากรณ์ setTimeout รับจำนวนเต็มเป็นพารามิเตอร์ตัวที่ 2
Andrew Hedges

คำตอบนี้ต้องการการทำงาน มันเป็นสุดยอดของความคิดเห็นหนึ่งรายการขึ้นไปและเป็นคำตอบหรือคำตอบแยกต่างหาก
Brian Webster

8

นี่เป็นหนึ่งในสถานการณ์ที่ PHP เป็นตัวเลือกที่แย่มาก ดังที่ได้กล่าวไว้ก่อนหน้านี้คุณสามารถผูกมัดพนักงาน Apache ทั้งหมดของคุณได้อย่างรวดเร็วทำสิ่งนี้ PHP ถูกสร้างขึ้นสำหรับการเริ่มต้นดำเนินการหยุด มันไม่ได้ถูกสร้างเพื่อเริ่มต้นรอ ... ดำเนินการหยุด คุณจะชะงักเซิร์ฟเวอร์ของคุณอย่างรวดเร็วและพบว่าคุณมีปัญหาในการปรับขนาดอย่างไม่น่าเชื่อ

ที่กล่าวว่าคุณยังสามารถทำสิ่งนี้กับ PHP และไม่ฆ่าเซิร์ฟเวอร์ของคุณโดยใช้ nginx HttpPushStreamModule: http://wiki.nginx.org/HttpPushStreamModule

คุณตั้งค่า nginx ต่อหน้า Apache (หรืออย่างอื่น) และมันจะดูแลการเปิดการเชื่อมต่อพร้อมกัน คุณเพียงแค่ตอบกลับด้วย payload โดยการส่งข้อมูลไปยังที่อยู่ภายในซึ่งคุณสามารถทำกับงานพื้นหลังหรือเพียงแค่ส่งข้อความไปยังคนที่รออยู่เมื่อใดก็ตามที่มีคำขอใหม่เข้ามาสิ่งนี้ทำให้กระบวนการ PHP ไม่เปิดในระหว่างการเลือกตั้งนาน

นี่ไม่ใช่เอกสิทธิ์ของ PHP และสามารถทำได้โดยใช้ nginx กับภาษาแบ็กเอนด์ โหลดการเชื่อมต่อที่เปิดพร้อมกันจะเท่ากับ Node.js ดังนั้นข้อได้เปรียบที่ยิ่งใหญ่ที่สุดคือมันทำให้คุณออกจาก NEEDING Node สำหรับสิ่งนี้

คุณเห็นผู้คนจำนวนมากพูดถึงห้องสมุดภาษาอื่น ๆ สำหรับการทำโพลแบบยาวและนั่นคือเหตุผลที่ดี PHP นั้นไม่ได้สร้างมาเพื่อพฤติกรรมประเภทนี้


นี่เป็นปัญหา Apache หรือปัญหา PHP หรือไม่ ฉันจะมีปัญหากับการทำโพลแบบยาวหรือไม่หากโค้ด PHP ของฉันรันบน nginx หรือ lighttpd โดยตรง
David

มันน้อยกว่าปัญหา PHP และการใช้ PHP ในทางที่ผิด ในทุกคำร้องขอ PHP จะเรียกใช้สคริปต์ตั้งแต่เริ่มต้นโหลดไลบรารีตามต้องการเรียกใช้งานโค้ดจากนั้นปิดเครื่องในขณะที่การรวบรวมขยะทุกอย่างเริ่มต้นในคำขอ มีการปรับเปลี่ยน PHP เป็นจำนวนมากในช่วงหลายปีที่ผ่านมาเพื่อลดผลกระทบเช่นการผูกแบบคงที่ช้าการโหลดแบบขี้เกียจในหน่วยความจำแคช bytecode เพื่อลบดิสก์ I / O เป็นต้นปัญหายังคงอยู่ที่ PHP ตั้งใจจะเริ่มและหยุดอย่างรวดเร็ว เป็นไปได้. ภาษาที่จะโหลดหนึ่งครั้ง / boot และเปิดเธรดสำหรับคำขอนั้นเหมาะสำหรับการทำโพลแบบยาว
brightball

แต่เพื่อตอบคำถามใช่คุณจะประสบปัญหาไม่ว่าคุณจะใช้ Apache หรืออย่างอื่น มันเป็นวิธีการทำงานของ PHP ฉันควรแก้ไขสิ่งนี้เพื่อบอกว่าถ้าคุณกำลังจะมีปริมาณการรับส่งข้อมูลสูงสุด PHP จะไม่เป็นไร ฉันเคยเห็นระบบฝังตัวที่ใช้ PHP ที่ไม่มีปัญหาเพราะมีเพียงการเชื่อมต่อเพียงไม่กี่อย่าง อาจเกิดขึ้นกับอินทราเน็ตของ บริษัท ซึ่งอาจผ่านได้ สำหรับแอปพลิเคชันที่ต้องเผชิญกับสาธารณะคุณจะต้องฆ่าเซิร์ฟเวอร์ของคุณอย่างแน่นอนเมื่อปริมาณการใช้งานเพิ่มขึ้น
brightball

4

ทำไมไม่ลองพิจารณาเว็บซ็อกเก็ตแทนการทำโพลแบบยาว? มีประสิทธิภาพและติดตั้งได้ง่าย อย่างไรก็ตามพวกเขาได้รับการสนับสนุนเฉพาะในเบราว์เซอร์ที่ทันสมัย นี่คือการอ้างอิงอย่างรวดเร็ว


ฉันคิดว่าเมื่อมีการติดตั้งเว็บซ็อคเก็ตทุกที่ (อาจจะไม่ใช่ในอีกหลายปีข้างหน้า) พวกเขาจะเป็นมาตรฐานสำหรับแอปพลิเคชันประเภทนี้ น่าเสียดายที่ตอนนี้เราไม่สามารถเชื่อถือได้สำหรับแอปที่ใช้งานจริง
Richard

3
@Richard แต่คุณสามารถใช้สิ่งที่ต้องการ Socket.IO ซึ่งให้บริการขนส่งทางเลือกโดยอัตโนมัติให้การทำงานเหมือนเว็บซ็อกเก็ตตลอดทางลงไปที่ IE 6
Brad

3

กลุ่ม WS-I ได้เผยแพร่สิ่งที่เรียกว่า"โปรไฟล์ความปลอดภัยที่เชื่อถือได้"ซึ่งมีการใช้งาน Glass Fish และ. NETซึ่งเห็นได้ชัดว่าใช้งานได้ดี

โชคดีที่มีการใช้Javascriptออกมีเช่นกัน

นอกจากนี้ยังมีการใช้ Silverlight ที่ใช้HTTP Duplex คุณสามารถเชื่อมต่อจาวาสคริปต์กับวัตถุSilverlightเพื่อรับการเรียกกลับเมื่อเกิดการพุช

นอกจากนี้ยังมีรุ่นจ่ายเชิงพาณิชย์เช่นกัน


2

สำหรับการนำ ASP.NET MVC ไปใช้ให้ดูที่ SignalR ซึ่งมีอยู่ใน NuGetโปรดทราบว่า NuGet มักจะล้าสมัยจากแหล่ง Gitซึ่งได้รับการยอมรับบ่อยครั้ง

อ่านเพิ่มเติมเกี่ยวกับ SignalR ในบล็อกของ Scott Hanselman


2

คุณสามารถลอง icomet ( https://github.com/ideawu/icomet ) เซิร์ฟเวอร์ดาวหาง C1000K C ++ ที่สร้างด้วย libevent icomet ยังมีห้องสมุด JavaScript ซึ่งใช้งานง่ายเหมือน

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 รองรับเบราว์เซอร์และระบบปฏิบัติการที่หลากหลายรวมถึง Safari (iOS, Mac), IEs (Windows), Firefox, Chrome, ฯลฯ


0

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

สถานการณ์การผลิตที่ชาญฉลาดใน Express สำหรับ exmaple คุณจะได้รับresponseในมิดเดิลแวร์ ทำสิ่งที่คุณต้องทำสามารถกำหนดขอบเขตวิธีการสำรวจความยาวทั้งหมดในแผนที่หรือบางสิ่งบางอย่าง (ที่สามารถมองเห็นได้กับกระแสอื่น ๆ ) และเรียกใช้<Response> response.end()เมื่อใดก็ตามที่คุณพร้อม ไม่มีอะไรพิเศษเกี่ยวกับการเชื่อมต่อแบบสำรวจระยะไกล ส่วนที่เหลือเป็นเพียงวิธีที่คุณจัดโครงสร้างแอปพลิเคชันตามปกติ

หากคุณไม่รู้ว่าฉันหมายถึงอะไรโดยการกำหนดขอบเขตสิ่งนี้จะทำให้คุณมีความคิด

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

อย่างที่คุณเห็นคุณสามารถตอบสนองต่อการเชื่อมต่อทั้งหมดอย่างใดอย่างหนึ่งทำในสิ่งที่คุณต้องการ มีidสำหรับทุกคำขอดังนั้นคุณควรจะสามารถใช้แผนที่และเข้าถึงเฉพาะการโทรออกจาก API

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.