采用PHP实现"服务器推"技术的聊天室

· 作者:laruence( http://www.laruence.com/)
· 本文地址: http://www.laruence.com/2008/04/16/118.html
· 转载请注明出处

  传统的B/S结构的应用程序,都是采用"客户端拉"结束来实现客户端和服务器端的数据交换。
  本文将通过结合Ticks(可以参看我的另外一篇文章: 关于PHP你可能不知道的-PHP的事件驱动化设计 ),来实现一个服务器推的PHP聊天室简单构想。

  PHPer,尤其是用过set_cookie, header的,一定见过这样的提示信息:"Warning: Cannot modify header information - headers already sent by.....", 这是因为通过HTTP协议通信,数据包会包含俩个部分,一个是Header,一个是data。一般来说,都是先Header部分,在Heaer部分指明了Data部分的长度,然后使用/r/n/r/n来表示header部分结束,接下来是Data部分。

  当我们有任何输出的时候,Header部分就发送了,这个时候,你再想header函数来改变一些Header部分的域信息,就会得到上面的提示信息。
  
   一个简单的办法就是使用output_buffering。让它来缓存服务器的输出,不要太早将Header部分发给客户端。

   那么,如果不使用output_buffering,是不是就可以实现,每当服务器有输出,就立即发送给客户端呢?

   做个如下试验:
// 设置php.ini中output_buffering=0 或者使用ob_end_flush()关闭缓存

set_time_limit ( 0 );
for ( $i = 0 ; $i < 10 ; $i ++ ){
  
echo   " Now Index is : " .   $i ;
  
sleep ( 1 );
}

  结果我们发现,还是要等到脚本全部执行完以后,才能一次看到所有的结果。。
  为什么呢?
  这是因为我们只是解决了缓存问题,但是还有一个缓冲问题,PHP会缓冲程序的输出。所以,这个时候,我们还需要调用,flush(), 来强制使得PHP将所有的程序输出发送给客户端。
// 设置php.ini中output_buffering=0
ob_end_flush (); // 关闭缓存

set_time_limit ( 0 );
for ( $i = 0 ; $i < 10 ; $i ++ ){
  
echo   " Now Index is : " .   $i ;
  
flush ();
  
sleep ( 1 );
}

    现在是不是看到了,不断有服务器的数据显示出来?

    有几个概念之间的关系,我这里补充以下:
    在代码中使用ob_start(), 就相当于在php.ini中使用output_buffering=on一样,使用服务器缓存。
    在代码中使用ob_end_flush() 就相当于在php.ini中使用output_buffering = false一样,关闭服务器缓存。
   
     基于前面的讨论,我们就有可能使用Ticks来实现,一个无刷新,无ajax的聊天室: 页面中包含俩个iframe,一个是不断获取聊天室的聊天内容,一个包含用户发表聊天内容的form. 这样,在第一个frame的脚本中:

ob_end_clear();
// 关闭缓存
set_time_limit ( 0 );
ob_implicit_flush(); 
// 这个语句将强制每当有输出就自动刷新,相当于在每个echo后,调用flush()
$new_mesg   =   NULL ;
register_tick_function ( " getNewMesg " );
declare (ticks = 1 ){
  
while ( 1 ){
     
if ( ! is_null ( $new_mesg )){
          
foreach ( $new_mesg   as   $msg ){
                
echo   $msg ;
          }
          
$new_mesg   =   null ;
     }     
  }
}

function  getNewMesg(){
// 通过查询数据库,或者共享内存,来获取现在的聊天室大厅的内容。
//返回一个数组,包含所有的新的聊天内容

}

 这样就实现了一个简单的使用服务器推技术的聊天室的框架。
 当然,关于实时输出,还有一些其他的限制,比如在PHP5手册中讲到的:
个别web服务器程序,特别是Win32下的web服务器程序,在发送结果到浏览器之前,仍然会缓存脚本的输出,直到程序结束为止。

有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。

甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape 浏览器会在接受到换行或 html 标记的开头之前缓存内容,并且在接受到 
</ table >  标记之前,不会显示出整个表格。

一些版本的 Microsoft Internet Explorer 只有当接受到的256个字节以后才开始显示该页面,所以必须发送一些额外的空格来让这些浏览器显示页面内容。

 接下来,我贴一个很有趣的代码,有兴趣的同学,可以试试:

header ( ' Content-type: multipart/x-mixed-replace;boundary=endofsection ' );
print   " --endofsection " ;
$pmt   =   array ( " - " ,   " / " ,   " | " ,   " / "  );
for $i   =   0 $i   < 10 ; $i   ++  )
{
        
sleep ( 1 );
        
print   " Content-type: text/plain " ;
        
print   " Part $i " . $pmt [ $i   %   4 ];
        
print   " --endofsection " ;
        
ob_flush ();  // 强制将缓存区的内容输出
         flush ();  // 强制将缓冲区的内容发送给客户端
}
print   " Content-type: text/plain " ;
print   " The end " ;
print   " --endofsection-- " ;
  使用firefox打开,看看你看到了什么。
  这个例子,使用了ob_flush(), 这样可以在代码中控制缓存区内容的输出时机,更加灵活一些。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值