+ -
当前位置:首页 → 问答吧 → 在线实时聊天的实现方案讨论

在线实时聊天的实现方案讨论

时间:2010-05-12

来源:互联网

在线实时聊天系统,一直是一个比较麻烦的东西。

一般实现在线实时聊天,是利用JS在客户端使用ajax每隔一定的时间就返回服务器请求数据,如果有新的聊天信息则用JS呈现给用户

我们不说这样做的利弊,直接切入正题,如何来实现服务器推的在线聊天系统

首先,我先请大家看一个例子

复制代码
  1. <?php
  2. while(true){
  3.         echo "这是一条信息<br />";
  4.         flush();
  5.         sleep(1);
  6. }
  7. ob_end_flush();
  8. ?>

运行后看到什么?是不是每隔一秒就输出一次“这是一条信息”?
这个就可以让我们模拟实现服务器推了

这里先说明一点。例子里面的聊天系统是基于数据库的。当然了,也可以是基于文件系统的,但是基于文件的就比较麻烦了。我们选个简单的,说清楚道理就可以了。

文件的结构如下:

chat.php 主页文件

msgshow.php   聊天信息展示文件

send.php  聊天信息发送文件

conn.php  数据库接口文件


数据表如下

chat表:
msgid  聊天信息ID
msg     信息内容
sendtime    发送时间
senduser   发送人姓名

好,我们正式开始

chat.php文件中,有一个浮动框架连接到msgshow.php文件

chat.php文件代码如下

复制代码
  1. <?php
  2. header ( 'Content-Type:text/html;charset=utf-8' );
  3. ?>
  4. <html>
  5. <head>
  6. <title>实时聊天测试</title>
  7. </head>
  8. <body>
  9. <iframe src="chat.php" height=200 width=200>
  10. </iframe>
  11. </body>
  12. </html>


msgshow.php文件代码如下

复制代码
  1. <?php
  2. require "conn.class.php";
  3. set_time_limit(0);
  4. $conn=new conn();
  5. $times*****p=time();   //这里请注意时区的设置
  6. print str_repeat(' ',4096);  //输出4096个空格,因为有的服务器自带有输出缓存,只有达到一定大小或PHP脚本运行完毕后才将内容输出,这一大小一般为4096个字节
  7. while(true){
  8.    
  9.     if(connection_aborted()){
  10.         break;
  11.     }
  12.     //读取所有的新的聊天信息
  13.     $chatData= $conn->fetchAll("select * from chat where sendtime>=$times*****p");
  14.     //遍历聊天信息并输出
  15.     if(!empty($chatData)&&is_array($chatData)){
  16.         foreach ($chatData as $data){
  17.              echo "$data[senduser]说:$data[msg]      $data[sendtime]<br />";
  18.         }
  19.     }
  20.  
  21.     $chatData=array();
  22.     $times*****p=time();//注意,这里$tiems*****p=time()这一步不可放到sleep的后面。
  23.     sleep(1.1);
  24.     ob_flush();//这二句代码强制将当前输出的内容全部发送到浏览器
  25.     flush();
  26. }
  27. ?>


简单起见,我们模拟一个用户点击发表按钮发言的动作,即:send.php完成的功能
代码如下

复制代码
  1. <?php
  2. require "conn.class.php";
  3. $conn=new conn();
  4. $time=time();
  5. $conn->query("INSERT INTO chat (msg,sendtime,senduser) VALUES ('测试信息<br />',$time,'testuser')");
  6. ?>

好,现在先试试可不可以正确执行。用浏览器访问chat.php
另开一个页面,访问send.php。然后试着去刷新send.php,看chat.php中是否会显示出“测试信息”字样。如果显示出来,说明测试成功

在我电脑上进行的测试,是使用了firefox和ie模拟两个用户进入聊天室,并且在两个浏览器中同时访问send.php文件并,随机刷新,来模拟两个用户随机发言。测试通过

我不得不说,这么做的效率可以说是非常的低下,如果一个聊天室有200用户,那么这200个用户在同一时间内要查询200次数据库来获取自己需要的信息。而这个信息往往又是相同的。因此,我们可以设计一个缓存模块来将一个聊天室的信息进行缓存,当200个运行中的msgshow.php不再去读取数据库,而是直接读取缓存文件,如果文件存在直接读取并格式化输出即可。至于缓存如何更新,那可以采用定时更新的方法,每1秒钟更新一次。前面我们已经看到,msgshow.php文件每次读取数据前,间隔时间为1.1秒,这也保证了,同一秒内不会读取到相同的缓存文件(每秒钟缓存文件为不同文件)。而一旦我们有了缓存模块后,数据库其实可以废弃。直接写入缓存文件中就可以了。这个是聊天室,至于点对点的双人聊天,还是使用数据库吧,不然文件实在是。。。太多了。即使是聊天室中,也是要定时清理缓存文件的,这对加速文件的读取是有好处的,比如你可以规定每个小时清理一次。我个人觉得可能的话还是使用memcached比较好。这方面就不再多说了。

我认为,在实际的应用中还是使用客户端拉数据的方式比较妥当,毕竟这方面比较成熟

以上内容属于个人观点,因为知识有限,难免有错误之处,希望大家看到后,可以回复指出,供给大家一起研究讨论。

作者: huaihuajio   发布时间: 2010-05-12

不错,很好的想法,不过自己没有实现,
狂支持你~~

作者: figo0505   发布时间: 2010-05-12

哇哈哈哈,当然了,不过我在考虑这么做的可行性。有的服务器是一个PHP程序就一个进程,如果访问的人数一多的话。。。。

作者: huaihuajio   发布时间: 2010-05-12

有什么想法就把他实现,遇到什么困难,大家一起解决,不是更好,一起进步嘛~~

作者: figo0505   发布时间: 2010-05-12

其实我心里已经有底了。在线聊天室,没有太大的难度。我已经做过一个基于ajax的了。
而用PHP做出来的网页聊天室,负载能力有限,因为对数据库的操作过于频繁了,我正考虑还是使用基于文件比较好,如果有空,再试试memcached。
嘿嘿~~
最近是没时间了,手头上还有个设计没做好。唉。。破玩意学校

作者: huaihuajio   发布时间: 2010-05-12

牛B。。

作者: energy162   发布时间: 2010-06-13

作者: ting1991s   发布时间: 2010-06-16

4 楼的是大学生啊?

作者: borfee   发布时间: 2010-09-06