Comet推送的两种方式(转)

因公司做项目要求有一个面要实时获取最新数据。效果类似于实时聊天,或者淘宝支付页面(当手机上支付成功后)会自动跳转,还有就是微信手网页版(当用手机扫了页面上的二维码并确定后)也会自动跳转。

经过上百度和谷歌查询找到了一些有用的信息,现记录下来方便查阅。

comet相关资料:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/

Comet是一种用于web的推送技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式:长轮询(long-polling)和iframe流(streaming)。

一、长轮询

长轮询就是客户端发起ajax请求,服务端会挂起该请求(通过循环),直到条件触发使服务器返回,在服务器返回前客户端一直处于pending,等待服务器返回。

长轮询可以减少客户端的无用请求,不过服务端的压力会大一些。另外可以采用websocket实现推送,不过兼容性会差些,有些浏览器不支持websocket。

服务端代码:

1 <?php 
2 //server.php 服务端  
3 set_time_limit(0); 
4 $filename './phplog.com/data.txt'
5 //模拟新消息到来 
6 if (!empty($_GET['m'])) { 
7     file_put_contents($filename$_GET['m']); 
8     exit(0); 
9
10 $old filemtime($filename); 
11 $cur filemtime($filename); 
12 while $cur <= $old) { 
13     usleep(500000);//休息500ms 
14     clearstatcache(); 
15     $cur filemtime($filename); 
16
17 echo file_get_contents($filename
18  ?> 

客户端代码:

1 <!doctype html> 
2 <html lang="en"
3 <head
4     <meta charset="UTF-8"
5     <script src="../phplog.com/jquery-1.9.0.min.js"></script
6     <title>PHP日志</title>
7 </head
8 <body
9     <button id="click1">click1</button
10     <script
11     var sending=false; 
12     $(function(){ 
13         $("#click1").click(function(){ 
14             $.ajax({ 
15                 type:"POST", 
16                 url:"server.php", 
17                 timeout:0, 
18                 beforeSend:function(){ 
19                     if (sending) { 
20                         return false; 
21                     
22                     sending = true; 
23                 }, 
24                 data:"username=eddy&password=123456", 
25                 success:function(data){ 
26                     alert(data); 
27                 }, 
28                 error:function(data){ 
29                     
30                 }, 
31                 complete:function(){ 
32                     sending=false; 
33                     $("#click1").click(); 
34                 
35             }); 
36         }); 
37     }); 
38     </script
39 </body
40 </html

点击click1按钮,发起请求,等待服务端返回(新消息到来)。此时可通过访问 /server.php?m=1234568798798000 模拟消息到达,消息到达服务端返回数据,客户端弹出消息内容。

二、iframe流

iframe 是很早就存在的一种 HTML 标记, 通过在 HTML 页面里嵌入一个隐蔵帧,然后将这个隐蔵帧的 SRC 属性设为对一个长连接的请求,服务器端就能源源不断地往客户端输入数据。

通过iframe里的内容进行长时间的请求,当需要传输内容时通过调用父页面js方法来实现页面展示,以此达到comet所需要的效果。

使用iframe流的一个不足就是在IE、opera、chrome浏览器下,始终会显示下载没完成,并且鼠标及浏览器上的那个圈一直在转动,在 IE678下,google的大牛们通过使用“htmlfile”解决了这个问题,IE9我试了,并不支持”htmlfile”,当然IE9那个圈已经不 转了。但是opera、chrome不支持“htmlfile”,无法解决。

iframe的另一个问题就是请求的超时,我们需要判断当iframe超时时,对其刷新重新建立连接。在普通情况下,我们可以通过iframe的 onload事件进行刷新,当iframe连接内容超时时就会触发onload事件。在“htmlfile”下iframe却不支持onload,但是能 读取到iframe的readyState,当readyState为complete时即表示请求超时,所以我们可以通过setInterval来判断 iframe的readyState进行刷新。

后台代码:

1 <?php
2 header("Cache-Control: no-cache, must-revalidate");
3 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
4 flush();
5 ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
6 <html xmlns="http://www.w3.org/1999/xhtml">
7 <head>
8   <title>PHP日志</title>
9   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
10 </head>
11 <body>
12 <script type="text/javascript">
13   // KHTML browser don't share javascripts between iframes
14   var is_khtml = navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML");
15   if (is_khtml)
16   {
17     var prototypejs = document.createElement('script');
18     prototypejs.setAttribute('type','text/javascript');
19     prototypejs.setAttribute('src','prototype.js');
20     var head = document.getElementsByTagName('head');
21     head[0].appendChild(prototypejs);
22   }
23   // load the comet object
24   var comet = window.parent.comet;
25 </script>
26 <?php
27 while(1) {
28   echo '<script type="text/javascript">';
29   echo 'comet.printServerTime('.time().');';
30   echo '</script>';
31   flush(); // used to send the echoed data to the client
32   sleep(1); // a little break to unload the server CPU
33 }
34 ?>
35 </body>
36 </html>

前端代码:

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <title>PHP日志</title>
5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6 <script type="text/javascript">
7 var comet = {
8     connection : false,
9     iframediv : false,
10     timer : 0,
11     initialize: function() {
12         if (!-[1,]) {
13             // For IE browsers
14             comet.connection = new ActiveXObject("htmlfile");
15             comet.connection.open();
16             comet.connection.write("<html>");
17             comet.connection.write("<script>document.domain = '"+document.domain+"'");
18             comet.connection.write("</html>");
19             comet.connection.close();
20             comet.iframediv = comet.connection.createElement("div");
21             comet.connection.appendChild(comet.iframediv);
22             comet.connection.parentWindow.comet = comet;
23             comet.iframediv.innerHTML = "<iframe id='comet_iframe' name='comet_iframe' src='./backend.php'></iframe>";
24             var comet_iframe = comet.connection.getElementById("comet_iframe");
25             comet.timer = window.setInterval(function(){
26                 if(comet_iframe.readyState === "complete"){
27                     comet_iframe.src = comet_iframe.src;
28                 }
29             },1000*65)
30         }else{
31             comet.connection = document.createElement('iframe');
32             comet.connection.onload = function(){
33                 comet.connection.src = comet.connection.src;
34             }
35             comet.connection.setAttribute('id','comet_iframe');
36             comet.connection.setAttribute('src','./backend.php');
37             comet.connection.style.display = "none";
38             document.body.appendChild(comet.connection);
39         }
40     },
41     // this function will be called from backend.php 
42     printServerTime: function (time) {
43         document.getElementById('content').innerHTML = time;
44     },
45     onUnload: function() {
46         if (comet.connection) {
47             comet.connection = false; // release the iframe to prevent problems with IE when reloading the page
48         }
49     }
50 }
51 window.onload = function(){
52     comet.initialize();
53 }
54 window.onbeforeunload = function(){
55     comet.onUnload();
56 }
57 </script>
58 </head>
59 <body>
60 <div id="content">The server time will be shown here</div>
61 </body>
62 </html>

posted on 2014-07-10 12:04  混元真人  阅读(561)  评论(1编辑  收藏  举报