It's simpler than I initially thought.. Basically you have a page that does nothing, until the data you want to send is available (say, a new message arrives).
(这比我最初的想法简单。基本上你有一个什么都不做的页面,直到你想要发送的数据可用(比如,新消息到达)。)
Here is a really basic example, which sends a simple string after 2-10 seconds.
(这是一个非常基本的例子,它在2-10秒后发送一个简单的字符串。)
1 in 3 chance of returning an error 404 (to show error handling in the coming Javascript example) (三分之一的机会返回错误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));
?>
Note: With a real site, running this on a regular web-server like Apache will quickly tie up all the "worker threads" and leave it unable to respond to other requests.. There are ways around this, but it is recommended to write a "long-poll server" in something like Python's twisted , which does not rely on one thread per request.
(注意:对于一个真实的站点,在像Apache这样的常规Web服务器上运行它会快速占用所有“工作线程”并使其无法响应其他请求..有很多方法可以解决这个问题,但建议写一下像Python一样扭曲的“长轮询服务器”,它不依赖于每个请求的一个线程。)
cometD is an popular one (which is available in several languages), and Tornado is a new framework made specifically for such tasks (it was built for FriendFeed's long-polling code)... but as a simple example, Apache is more than adequate! (cometD是一种流行的(有多种语言版本可供选择),而Tornado是一个专门为这些任务而设计的新框架(它是为FriendFeed的长轮询代码而构建的)......但作为一个简单的例子,A??pache绰绰有余!)
This script could easily be written in any language (I chose Apache/PHP as they are very common, and I happened to be running them locally) (这个脚本很容易用任何语言编写(我选择了Apache / PHP,因为它们非常常见,我碰巧在本地运行它们))
Then, in Javascript, you request the above file ( msg_srv.php
), and wait for a response.
(然后,在Javascript中,您请求上述文件( msg_srv.php
),并等待响应。)
When you get one, you act upon the data. (当你得到一个,你就会对数据采取行动。)
Then you request the file and wait again, act upon the data (and repeat) (然后你请求文件并再次等待,对数据采取行动(并重复))
What follows is an example of such a page.. When the page is loaded, it sends the initial request for the msgsrv.php
file.. If it succeeds, we append the message to the #messages
div, then after 1 second we call the waitForMsg function again, which triggers the wait.
(以下是这样一个页面的示例..当页面加载时,它发送msgsrv.php
文件的初始请求。如果成功,我们将消息附加到#messages
div,然后在1秒后我们调用再次使用waitForMsg函数,触发等待。)
The 1 second setTimeout()
is a really basic rate-limiter, it works fine without this, but if msgsrv.php
always returns instantly (with a syntax error, for example) - you flood the browser and it can quickly freeze up.
(1秒的setTimeout()
是一个非常基本的速率限制器,如果没有这个,它可以正常工作,但是如果msgsrv.php
总是立即返回(例如语法错误) - 你会淹没浏览器并且它可以快速冻结。)
This would better be done checking if the file contains a valid JSON response, and/or keeping a running total of requests-per-minute/second, and pausing appropriately. (最好检查文件是否包含有效的JSON响应,和/或保持每分钟/秒的运行总计请求,并适当地暂停。)
If the page errors, it appends the error to the #messages
div, waits 15 seconds and then tries again (identical to how we wait 1 second after each message)
(如果页面错误,它会将错误附加到#messages
div,等待15秒然后再次尝试(与每条消息后等待1秒的方式相同))
The nice thing about this approach is it is very resilient.
(这种方法的好处是它非常有弹性。)
If the clients internet connection dies, it will timeout, then try and reconnect - this is inherent in how long polling works, no complicated error-handling is required (如果客户端互联网连接中断,它将超时,然后尝试重新连接 - 这是轮询工作多长时间所固有的,不需要复杂的错误处理)
Anyway, the long_poller.htm
code, using the jQuery framework:
(无论如何,使用jQuery框架的long_poller.htm
代码:)
<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>