手机局域网ip地址查询:COMET服务器推技术 - 实现Web服务器“主动”向客户端发送数据

来源:百度文库 编辑:中财网 时间:2024/04/29 13:28:43
在WEB开发中常常遇到一种需要即时更新内容的情况,比如在线聊天室,基于Web的IM系统或者股票查看系统等等。这些系统无一例外地要求内容更新的及时性。即每次有了新的内容,都必须即时发送给客户端。由于B/S架构的先天特性,即HTTP协议是一种无状态无链接协议,所以要实现服务器端主动发送数据给客户端,传统方法是难以实现的。为了解决这一问题,COMET服务器推技术便应运而生。

      在传统的解决方案中,对页面进行全部或者局部刷新,似乎是解决这一问题的唯一办法。早期基于Web的聊天室一般都采用这种方法。即在页面中插入一个隐藏的iframe,通过这个iframe不断地自动刷新来轮询服务器端以获得最新消息,亦或是采用AJAX技术,每相隔一段时间发起一次HTTP请求来更新内容。但是这种方法缺点是非常明显的。首先,延迟无法避免,没有办法做到完全的及时性。如果我们设定轮询间隔为5s,那么内容更新的最大延迟就会说5s。其次,为了追求及时性,频繁的刷新、轮询,会造成过大的服务器压力。当在线人数很多时,这种方法几乎就是变相的分布式拒绝服务攻击。

      那么有没有一种更加划算的方法呢?当然有的,比如使用activeX控件或者JAVA Applet等实现Socket通信。不过这种方法需要另外开端口,在网络情况复杂特别是存在防火墙的情况下,会造成通信失败。另外,使用Socket通信,还对服务器存在一定的要求,需要自己实现一套C/S模式的东西,这不符合Web开发的初衷。

      在HTTP中有一种长连接技术,可以模仿Socket通信实现服务器端主动向客户端浏览器发送数据。它的原理其实很简单:当服务器端接到客户端的询问请求后,将整个HTTP连接置于阻塞状态,即什么也不做,也不发送数据,也不关掉连接。直到客户端需要将最新数据返回给客户端时,将数据通过这个HTTP连接返回回去,并且关闭连接。这样,客户端看到的结果,就似乎是服务器端主动向客户端浏览器发送数据了。但是,关掉连接以后怎么办呢?这时候,可以通过客户端JS代码中的定时器,再次发起请求。这样,只有内容发生了变化,才会进行一次HTTP会话,所以整体效率比轮询方式要高出很多,同时还有了更好的及时性。

     在人人网中,页面中的即时消息提醒、在线IM就是通过这种方法实现的。另外,在WebQQ等基于WEB的IM中也广泛使用了这种技术。当然,在HTML5中,提供了专用的持久连接套接字,能够实现真正的服务器主动发送数据给客户端。

     那么如何用代码来实现这个COMET服务器推送呢?请看下面。这部分代码是我从网上收集过来的,基于PHP 和prototype库写成。详情参考http://www.blogjava.net/JAVA-HE/archive/2009/04/13/265249.html
PHP服务器端代码:
view plaincopy to clipboardprint
  1. $filename  = dirname(__FILE__).'/data.txt';   
  2. $msg = isset($_GET['msg']) ? $_GET['msg'] : '';   
  3. if ($msg != '')   
  4. {   
  5.   //写入内容至文件   
  6.   file_put_contents($filename,$msg);   
  7.   die();   
  8. }   
  9. set_time_limit(0);   
  10. $lastmodif    = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;   
  11.   
  12. //取得文件最后修改时间   
  13. $currentmodif = filemtime($filename);   
  14.   
  15. while ($currentmodif <= $lastmodif)    
  16. {     
  17.   //有释放CPU占用率的作用   
  18.     usleep(10000);    
  19.     //清除文件缓存信息   
  20.     clearstatcache();   
  21.     $currentmodif = filemtime($filename);   
  22. }   
  23.   
  24. // return a json array   
  25. $response = array();   
  26. $response['msg']       = file_get_contents($filename);   
  27. $response['timestamp'] = $currentmodif;   
  28. echo json_encode($response);   
  29. ob_flush();   
  30. flush();   
  31. ?>   


JS客户端代码:

view plaincopy to clipboardprint
  1. /*****************************************  
  2.  *   @Description : Comet TEST  
  3.  *  @FileName    : comet.js  
  4.  *   @Author      : He Chang Min   
  5.  *   @Date        : 2009-03-05  
  6.  *   @Comment     :   
  7.  ******************************************/  
  8.   
  9. var WebApp =    
  10. {   
  11.   //程序入口函数   
  12.   WebMain : function()   
  13.     {   
  14.       var ajax = new Ajax.Request(WebApp._url_,    
  15.     {   
  16.       method: 'get',   
  17.       parameters: { 'timestamp' : WebApp._timestamp_ },   
  18.         onSuccess: function(transport)    
  19.       {   
  20.             var response = transport.responseText.evalJSON();   
  21.             WebApp._timestamp_ = response['timestamp'];   
  22.             WebApp.handleResponse(response);   
  23.             WebApp._noerror_ = true;   
  24.         },   
  25.         onComplete: function(transport)    
  26.       {   
  27.             if (!WebApp._noerror_)   
  28.         {   
  29.               setTimeout(WebApp.WebMain, 5000);    
  30.         }else  
  31.               {    
  32.           setTimeout(WebApp.WebMain, 10);    
  33.         }   
  34.             WebApp._noerror_ = false;   
  35.           }   
  36.     });   
  37.   },   
  38.     handleResponse : function(response)   
  39.     {   
  40.       $('content').innerHTML += '
    ' + response['msg'] + '
    ';   
  41.     },   
  42.     doRequest : function(request)   
  43.     {   
  44.       new Ajax.Request(WebApp._url_,    
  45.     {   
  46.           method     : 'get',   
  47.           parameters  : { 'msg' : request }   
  48.       });   
  49.     },   
  50.     //成员属性   
  51.     _timestamp_   : 0,   
  52.   _url_        : './comet.php',   
  53.     _noerror_      : true     
  54. }   


以下是代码的打包文件:下载文件 (已下载 209 次)点击这里下载文件: TestComet.rar

可以将代码上传到服务器上,然后打开两个不同的浏览器。从一方发送数据,可以看到另一方会立即显示出更新。

以下是本文的参考资料,想要了解更多的朋友可以前去访问:

浅谈comet技术  http://www.blogjava.net/JAVA-HE/archive/2009/04/13/265249.html

Comet:基于 HTTP 长连接的“服务器推”技术  http://www.ibm.com/developerworks/cn/web/wa-lo-comet/

实战 Comet 应用程序开发 http://www.ibm.com/developerworks/cn/web/wa-lo-w2fpak-comet/index.html

javaeye上的Comet相关文章 http://www.javaeye.com/wiki/topic/684909