聊天室服务器:PHP实现服务器推技术的聊天室来源: 发布时间:星期三, 2008年9月10日 浏览:92次 评论:0
传统的B/S结构的应用程序,都是采用\"客户端拉\"结束来实现客户端和服务器端的数据交换。
本文将通过结合Ticks(可以参看我的另外一篇文章:关于PHP你可能不知道的-PHP的事件驱动化设计),来实现一个服务器推的PHP聊天室简单构想。 PHPer,尤其是用过set_cookie,header的,一定见过这样的提示信息:\"Warning:Cannotmodifyheaderinformation-headersalreadysentby.....\",这是因为通过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\"NowIndexis:\".$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\"NowIndexis:\".$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_mesgas$msg){ echo$msg; } $new_mesg=null; } } } functiongetNewMesg(){ //通过查询数据库,或者共享内存,来获取现在的聊天室大厅的内容。 //返回一个数组,包含所有的新的聊天内容 } 这样就实现了一个简单的使用服务器推技术的聊天室的框架。 当然,关于实时输出,还有一些其他的限制,比如在PHP5手册中讲到的: 个别web服务器程序,特别是Win32下的web服务器程序,在发送结果到浏览器之前,仍然会缓存脚本的输出,直到程序结束为止。 有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。 [Page] 甚至浏览器也会在显示之前,缓存接收到的内容。例如Netscape浏览器会在接受到换行或html标记的开头之前缓存内容,并且在接受到</table>标记之前,不会显示出整个表格。 一些版本的MicrosoftInternetExplorer只有当接受到的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();//强制将缓冲区的内容发送给客户端 0
相关文章
读者评论
发表评论 |