PHP聊天室技术


Posted in PHP onOctober 09, 2006

PHP聊天室技术 黄国辉

1.前言

上网聊天是时下最流行的交友方式。各大网站推出的聊天室都各具特色。

聊天室主要分为WebChat、BBSChat两种。BBSChat是基于Telnet的Tcp协议,是BBS的附设功能,需要客户端Telnet程序。WebChat则采用浏览器方式,实际上是一个多人共同使用的CGI程序。其基本原理是把每个用户的发言通过浏览器传给系统,再由系统收集处理后分发给特定用户。

WebChat一般采用Server Push或Client Pull技术。两种技术的区别在于使用不同的方式将数据分发给用户,Server Push是由服务器将数据以多重MIME编码,推给(push)使用者端,目前较少网站使用这种方式。Client Pull则是用户从服务器拉(pull)所要的数据。

最常用的Client Pull就是利用Html语言的Meta标签http-equiv="Refresh" 的属性,每隔一段时间就检查服务器上是否有新的数据。例如,每隔5秒钟就会刷新一次页面。这种方法简单有效,缺点是刷新时会产生闪烁的现象;而且为了保持效率,每次刷新都会把旧的聊天内容清除,用户想查看或保留对话内容都很不方便。为此,采用JavaApplet作为聊天室的前端,利用刷新把从服务器Pull的数据通过JavaApplet来显示也是一种解决方案。还有就是本文要介绍的使聊天程序保持连线的方案。方法一,把聊天程序设置为无限大,就能使浏览器不停地保持下载的连线状态;方法二,聊天程序中存在着无限循环,因为可以方便地设置更高级的功能,所以在此选择采用。

Web服务器采用FreeBSD+Apache,原因是两者的组合具有最强的性能,而且花费为零。还需要考虑的是用什么方式来存放数据呢。用文件相对而言容易实现,但是多人使用,频繁地对同一文件进行IO操作,难免会影响效率,况且FreeBSD的IO性能不佳。可以考虑使用RamDisk,将文件整个放进内存,以提高速度。或者在内存中划分出一块高速空间用以数据存放。笔者使用的是数据库方式:MySQL。因为该数据库就是为大批量用户同时使用而设计,利用它可以省去设计高速空间操作的复杂编写,速度也可得到保证。如将整个数据库放进内存,效果更好。

程序用PHP+Html+JavaScript编写。聊天室主要是对Html的Form中的各种元素进行操作。JavaScript是基于对象的语言,对Html中的各种元素皆当作对象看待,所以每个元素的方法和属性都很丰富,操作比较方便。而PHP只有在Form经过Post后,将Form中的元素转成对应的变量,才能处理用户输入的数据。从交互性来说比较差,这也是使用JavaScript的原因。采用PHP的原因是因为比起其它CGI语言,其速度和安全性都较佳,开发也比较容易。

2. 不断刷新的聊天室

一个标准的聊天室页面由三个Frame组成,分别是显示在线用户的Online、用户发言及功能设置的Say和显示聊天内容的List。用户在Say Frame中敲入发言内容后按发送,数据经过处理后保存在Mysql数据库,同时被保存的还包括发言人、聊天对象及发言的时间。用户一进入聊天室,List Frame从Mysql数据库中把发言时间大于用户进入时间的发言提出显示出来。而后续显示新的发言内容的关键,在于显示聊天内容的那段程序是无限循环的。
List Frame程序概要:

$db=mysql_pconnect(localhost,root); #Mysql数据库连接 
mysql_select_db(chat,$db); 
显示欢迎进入聊天室 
设置$init为数据库中发言时间比 
进入时间大的第一个数据的ID号 #是数据提取的标志位 
while (1==1) { #无限循环开始 
提取从$init到最后的数据; 
while (每一个数据$text) { 
$emote=strip_tags($text); #防止用户直接输入Html语言 
if (eregi("^/",$emote)) #判断发言是否系统命令(以/开头) 
系统特殊处理 
else 显示发言 
} 
设置$init为最后数据的ID号 
flush(); #清出输出缓冲,使发言马上显示 
sleep(2); #使程序暂停2秒,节省系统资源 
mysql_free_result($result); #释放数据库结果占用的内存 
}

因为程序无限循环,在每次循环中输出的发言是先置入输出缓冲区内。通过flush()马上把缓冲区的内容向用户的List Frame送出,达到了实时的聊天效果。循环最后要释放Mysql结果集占用的内存,否则因为无限循环的缘故,系统资源很快会被耗尽。
用户在Login后将建立一个Online的表用于在线用户的统计,主要是为了防止User表过大,程序中频繁用到的检索会拖慢系统的运作。这其中用的最多的是Online Frame,在采用Client Pull的Refresh Meta,每隔一段时间就会查询Online表,以刷新在线的用户。如果用户不发言超过规定时间,系统会调用自定义函数将用户设为TimeOut,强制将其退出聊天室。

3. 用户功能简介

用户的功能设置在Say Frame中,可以选择发言贴图、说话的语气等。发言经过特殊的处理后存储到Mysql,例如选择了一个贴图后,系统将添加到发言的前面,就可以实现贴图的效果。
对于聊天室常用到的Emote,例如用户A输入“/hello”按发送,List Frame中显示出来的是“用户A愉快地和大家打招呼”,为了保持效率,用户输入的Emote会原文直接保存到数据库,而解析转换的工作由List Frame来完成。
悄悄话只有自己和聊天对象可以看到,实现上因为发言预先保存有发言人和聊天对象,只要做一个简单的判断即可。还有聊天室常有的屏蔽某用户发言的功能,通过设置一个临时的阵列来实现,没必要保存在用户的数据库中。
聊天室人多的时候,大家争先发言常使人眼花缭乱,这时可以选择是否屏蔽无关的发言,即意味着只要不是对所有人和自己的发言将不会显示出来。当然,因为系统会用特殊的颜色来标识和自己有关的发言,就算不选择该功能,用户还是能快速地从众多发言中找到和自己相关的。
用户可以在特定时间(系统比较空闲时)将当天和自己有关的发言打包。因为存储发言的表数据增长速度很快,为保持运行效率,系统隔天就会把它复制后清空。这样用户检索打包发言内容就不会影响聊天系统的运作。
出于安全的考虑,聊天室的管理功能是独立的,并没放在聊天页面中。主要有用户资料管理和将捣乱用户Kick Out(踢人)两种功能。将用户踢出聊天室后将使他在一定的时间内不能再进入聊天室。
聊天室的安全要求虽然不象电子商务那样高,但如果用户被冒名顶替、用户的发言被窃听,或者乱踢人,是非常令人不快的。用户都要在Login中填写名字和密码才能进入聊天室,但是通过查看Login的源代码,虽然不能看到Php的部分,Htnl部分的源码却显示Login是调用Chat.php程序从而进入聊天室的。所以为了防止用户直接进入聊天室,系统会首先判断新建立的聊天室是否由Login产生的,不是则退出。同理,在聊天室的List Frame和Post Frame也可加上这样的防护。当然,在List Frame和Post Frame中检查用户的身份和密码,就万无一失了,只是加重了系统的负担。
综上所述,能看到系统的源代码无疑是危险的开端,所以系统的编写尽量用看不到源码的Php;设置由Login开启的聊天室隐藏了浏览器的工具条、状态栏等,并且屏蔽了鼠标的右键及快捷键。

4. 总结

用Php编写的聊天室具有高效稳定的特点,是编写网络交互程序的最佳选择。

参考文献:
[1] Rasmus Lerdorf著. PHP Manual [M].电子文档,2000

PHP 相关文章推荐
PHP Session变量不能传送到下一页的解决方法
Nov 27 PHP
php 日期时间处理函数小结
Dec 18 PHP
PHP开发规范手册之PHP代码规范详解
Jan 13 PHP
PHP MySQL应用中使用XOR运算加密算法分享
Aug 28 PHP
php模板函数 正则实现代码
Oct 15 PHP
PHP数组无限分级数据的层级化处理代码
Dec 29 PHP
基于Zookeeper的使用详解
May 02 PHP
thinkphp实现面包屑导航(当前位置)例子分享
May 10 PHP
PHP中遇到BOM、编码导致json_decode函数无法解析问题
Jul 02 PHP
简单说说PHP优化那些事(经验分享)
Nov 27 PHP
PHP简单获取及判断提交来源的方法
Apr 22 PHP
php中static和const关键字用法分析
Dec 07 PHP
在windows iis5下安装php4.0+mysql之我见
Oct 09 #PHP
PHP安装攻略:常见问题解答(二)
Oct 09 #PHP
一个没有MYSQL数据库支持的简易留言本的编写
Oct 09 #PHP
NO3第三帝国留言簿制作过程
Oct 09 #PHP
基于数据库的在线人数,日访问量等统计
Oct 09 #PHP
PHP安装攻略:常见问题解答(三)
Oct 09 #PHP
繁体中文转换为简体中文的PHP函数
Oct 09 #PHP
You might like
php巧获服务器端信息
2006/12/06 PHP
str_replace只替换一次字符串的方法
2013/04/09 PHP
php中url函数介绍及使用示例
2014/02/13 PHP
JavaScript Archive Network 集合
2007/05/12 Javascript
Javascript实现DIV滚动自动滚动到底部的代码
2012/03/01 Javascript
jQuery使用技巧简单汇总
2013/04/18 Javascript
Javascript操作URL函数修改版
2013/11/07 Javascript
JS+CSS实现自适应选项卡宽度的圆角滑动门效果
2015/09/15 Javascript
JS实现网页上随滚动条滚动的层效果代码
2015/11/04 Javascript
jquery简单倒计时实现方法
2015/12/18 Javascript
Zero Clipboard实现浏览器复制到剪贴板的方法(多个复制按钮)
2016/03/24 Javascript
详细谈谈AngularJS的子级作用域问题
2016/09/05 Javascript
JS实现“隐藏与显示”功能(多种方法)
2016/11/24 Javascript
用原生js做单页应用
2017/01/17 Javascript
canvas的神奇用法
2017/02/03 Javascript
详解angular 中的自定义指令之详解API
2017/06/20 Javascript
jQuery基于Ajax实现读取XML数据功能示例
2018/05/31 jQuery
vue实现虚拟列表功能的代码
2020/07/28 Javascript
Python解析xml中dom元素的方法
2015/03/12 Python
常见python正则用法的简单实例
2016/06/21 Python
python try except 捕获所有异常的实例
2018/10/18 Python
Python删除n行后的其他行方法
2019/01/28 Python
基于Keras 循环训练模型跑数据时内存泄漏的解决方式
2020/06/11 Python
python3.6中anaconda安装sklearn踩坑实录
2020/07/28 Python
Pycharm Git 设置方法
2020/09/15 Python
html5+css3之制作header实例与更新
2020/12/21 HTML / CSS
HTML5 图片预加载的示例代码
2020/03/25 HTML / CSS
法拉利英国精品店:Ferraris Boutique UK
2019/07/20 全球购物
Ado与Ado.net的相同与不同
2014/12/08 面试题
外企求职信范文分享
2013/12/31 职场文书
民族学专业求职信
2014/07/28 职场文书
信用卡工作证明模板
2014/09/14 职场文书
2015年护理工作总结范文
2015/04/03 职场文书
2015年路政工作总结
2015/05/22 职场文书
Vue Element UI自定义描述列表组件
2021/05/18 Vue.js
pandas:get_dummies()与pd.factorize()的用法及区别说明
2021/05/21 Python