设为首页 收藏本站
查看: 1115|回复: 0

[经验分享] 采用PHP实现”服务器推”技术的聊天室

[复制链接]
发表于 2017-4-8 13:04:41 | 显示全部楼层 |阅读模式
  传统的B/S结构的应用程序,都是采用"客户端拉"结束来实现客户端和服务器端的数据交换。
本文将通过结合Ticks(可以参看我的另外一篇文章:关于PHP你可能不知道的-PHP的事件驱动化设计 ),来实现一个服务器推的PHP聊天室简单构想。
  PHPer,尤其是用过set_cookie, header的,一定见过这样的提示信息:"Warning: Cannot modifyheader 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,是不是就可以实现,每当服务器有输出,就立即发送给客户端呢?
  做个如下试验:

DSC0000.gif //设置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&lt;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()函数产生的结果不会立即被发送到客户端浏览器。

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

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


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


header(Content-type:multipart/x-mixed-replace;boundary=endofsection);
print" –endofsection ";
$pmt=array("-","/","|","/");
for($i=0;$i&lt;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"Theend ";
print"–endofsection– ";


  使用firefox打开,看看你看到了什么。
  这个例子,使用了ob_flush(), 这样可以在代码中控制缓存区内容的输出时机,更加灵活一些。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-362001-1-1.html 上篇帖子: 20 Promising Open Source PHP Content Management Systems(CMS) 下篇帖子: [转]解决PHP截取中文字符串问题
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表