- 浏览: 306388 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
jakejone:
起作用了,谢谢啦
java.sql.SQLException:Value '0000-00-00' can not be represented as java.sql.Date -
BadBoyPgm:
不错 工作中刚好用到 看看知道怎么回事
ServletContextListener 应用 -
ifox:
不错哦,这个有用。找了好久呢、
struts2 iterator status index -
输入法:
上面书籍里有详细介绍?
js 获取select option 值 value text -
feihuale:
不错。。。真好,,,,学习了。。。
The error occurred while applying a parameter map.
闲来无事,做了一个AJAX聊天室,以前一直想做一个,因为我和几个朋友是Linux机子,尽管我们的机子上都有apache服务器,但要发送一个信息却不是很容易,老是要借助客户端,有时候吧Linux下的qq和gtalk之类的聊天软件太麻烦,所以呢,就写了一个聊天室。
先说一下我实现的这个聊天室的聊天模式:
1,无须注册,登录之类,打开页面就可以聊天。
2,为避免过量冗余信息,客户端只获取在一定时间以后发送的信息,比如10秒内。
3,可以单对单聊天,仅限于一个对一个,如果想一对多同时聊天,那么就必须要注册登录才能解决。
这样就简化了一些聊天的模式了,如果想要实现例如qq,msn,gtalk之类的聊天模式,就必须要用到用户注册登录,这样一来,先有的很多ajax聊天程序都已经设计的很完美了,例如:
http://blog.jwchat.org/jwchat/
http://ajaxbber.sourceforge.net/index.php?page=home
还有很多,不一一列举。
分析一下原理:
客户端必须不断的刷新,向服务器获取信息和在线会员列表。我采用session验证,因为session够安全,但是在线会员是存入数据库的,因为如果在线会员比较多,存入数据库,远比用原来的session直接以文件形式存储的要快。session存入数据库,有专门讲解的,为了简化,这里只用到session_id 这个session_id其实在服务器端还是以文件形式存储的,先做两个表:
message( id , status, nick, to_uid, to_sid, to_ip, from_uid,from_sid,from_ip , message)
online(uid, sid, ip ,nick, message_id , lastupdate, tip , status , link_uid , link_sid, link_ip )
如果不实现单聊,表就可以简化为:
message( id , nick, from_uid,from_sid , from_ip , message) ,
online(uid, sid, ip ,nick, message_id , lastupdate, tip )
为了简化,分单独几道ajax请求和服务器通信:
1.获取信息,这个请求负责刷新获取信息,在线用户。 chat.php?ac=get
2.发送信息,这个请求负责向服务器发送信息。 chat.php?ac=send
3.请求连接,这个地方负责实现单聊连接的。 chat.php?ac=linkto
4.处理连接,处理接收或拒绝单聊请求。 chat.php?ac=cut
先来分析第一个发送请求,获取消息和在线会员。
客户端向服务器发出请求后,这里我采用这样的提交形式:chat.php?ac=get
先判断用户是否存在?
session_start();
$sid = session_id();
$ip = $_SERVER['REMOTE_ADDR'];
$dateline = time();
// 获取用户当前设置的昵称。
$nick=$_POST['nick']; // 如果你的ajax请求是get实现的,那么这里就改动一下。
$sql="SELECT * FROM online WHERE sid='$sid' AND ip='$ip' LIMIT 1 " ;
第一步就是要判断用户是否已经存在数据表中,没有,则表示是第一次登录,需要新建立一个用户。
这里同时采用了 sid 和 ip 来验证用户是否已经在表中存在,用ip主要是为了防止session被劫持。但如果是内网劫持,因为网关出口ip通常是一个,所以这一招基本没太大用处,可以不用判断ip,后来发现我这里其实是自找麻烦,因为有的公司的ip是不断变化的,我一个朋友的公司ip就是在两个直接随机切换,所以建议还是只判断sid就可以了,毕竟劫持session_id的可能性还是比较小的。
如果用户不存在,那么新插入一条数据就可以了。
如果用户存在,先刷新用户的最后更新时间,
$sql="UPDATE online SET nick='$nick',dateline='$dateline' WHERE sid='$sid' AND ip='$ip' LIMIT 1 ";
然后删除已经离线的用户:
$interval = 10 ; // 十秒没用刷新的话,就认为其已经离线了。
$sql="DELETE FROM online WHERE dateline < $dateline - $interval ";
获取在线会员
$sql="SELECT * FROM online WHERE 1 ";
获取用户自己:
$sql="SELECT * FROM online WHERE sid='$sid' ";
存入变量$user中。
获取信息。
$message_id=$user['message_id'] ? $user['message_id'] : 0;
// 这个$user变量就是我们前面获取的当前用户。
$sql="SELECT * FROM message WHERE dateline > $dateline-$interval AND id > $message_id AND from_sid != '$sid' AND status=1 ORDER BY dateline ASC";
解释一下,这里只获取当前时间-10以后的信息,那么以前的信息就不会获取了,也就是说不会像qq那样,即使你离线了,别人发给你的信息,在你下次登录后还能获取到。因为我们没用会员注册,所有的信息都是无定向的。
这里用 status=1表示信息是群聊的, status=0表示信息是单聊的。所以如果只想实现群聊,不想实现单聊的,就不用判断状态了。
在获取信息的同时需要更新用户的message_id,这个标志用来表示当前用户已经获取到哪条信息的位置了,如果没用这个标志,那么,每次刷新,用户上次获取过的信息,如果在10秒内,这次还会获取到,假设有人连续发送信息,那么客户端会获取到大量重复信息,当然,客户端可以用一个隐藏的文本框来存储当前用户已经获取到哪条信息了,这个方法既笨拙,又不实用,而且我好像见到有人就是这么做的。
while($row=mysql_fetch_array(mysql_query($sql)) ){
$message_id = $row['id'] > $message_id ? $row['id'] : $message_id ;
// 不论您是否采用这样的循环方式获取消息,您都应该把message表的取到的最大id记录下来。
}
下面获取单聊的信息。因为单聊的窗口通常会和群聊分开的。
$sql="SELECT * FROM message WHERE dateline > $dateline-$interval AND id > $message_id AND from_sid != '$sid' AND status=0 AND to_sid='$sid' order by dateline asc";
好下面在获取完单聊消息后,仍然需要执行:
$message_id = $row['id'] > $message_id ? $row['id'] : $message_id ;
以获取最大的消息id。
当然了,如果您觉得麻烦,完全可以这样:
$maxId_sql="SELECT max(id) FROM message";
因为我们每次取完消息后,必然会把当前所有的可用信息取完,只是这样做增加了一次数据库查询。
下面,更新用户表的 message_id;
$sql="UPDATE online SET message_id='$message_id' WHERE sid='$sid' AND ip='$ip' LIMIT 1";
好了,这样下次再取信息的时候,就会由这个message_id向后开始取,只取 id 比message_id大的信息。
吐出的最终数据最好是JSON格式的,这样也好减少流量,方便处理文本。
您总不希望别人发送给您信息的时候,发给你这样一个:<script> location.href="g.cn" ;</script>
这样你的页面啪的一声就转到google的主页了!
所以在前台处理的时候需要把将要提交的信息进行转义:
str.replace(/</g,'<').replace(/>/g,'>').replace(/'/g,''').replace(/"/g,'"');
在php端处理的时候就比较轻松了:htmlspecialchars( $_POST['msg'] );
好了,信息算是处理完成了,然后只要吐出就可以了:
header('Content-Type:text/html ; charset=UTF-8'); // 设定你的编码。
按照某些w3c mime标准来说,json吐出的格式应该是:application/json;
当然不推荐这么做,只需吐出 text,或html就可以了,这样做是方便调试。
我们在后台把所有取出的信息组合成一个大的数组:
$echo_json=array();
$echo_json['msg']=$msg ; // 取出的消息
$echo_json['online']=$online; // 取出的用户
echo json_encode( $echo_json );
当然,为了节约流量,最好把吐出的字母变量缩短,我就是这么干的。一个字母足够了。
2。发送信息。
$msg_status = 1; // 信息状态,1表示群,0表示私聊
$toip = $user['link_ip']; // 发送的目标对象信息直接由用户的表里取,如果没有单聊,省去。
$touid = $user['link_uid'];
$tosid = $user['link_sid'];
$nick = htmlspecialchars($_POST['nick']); // 这个是用户发送消息时的昵称。
$message = htmlspecialchars($_POST['message']); // 消息体。
$sql="INSERT INTO message(status,from_uid,from_sid,from_ip,to_uid,to_sid,to_ip,nick,dateline,message) VALUES('$msg_status','$uid','$sid','$ip','$touid','$tosid','$toip','$nick','$dateline','$message')";
插入消息体,如果有单聊的话,需要加上判断:
$sql="SELECT * FROM online WHERE sid='$link_sid' AND ip='$link_ip' LIMIT 1";
而如果不存在 $user2,单聊的对象,那么,返回失败消息,提示用户发送消息已失败,对象已断开。
好,吐出消息:
这里可用简化一下处理结果,如果发送消息成功了,那么什么也不返回,如果失败了返回0.
这样做为了省流量。因为毕竟发送消息成功的时候比较多,失败比较少。在客户端用js取出返回的数据
判断是否为空,为空,则,发送成功,不为空,则发送失败。
echo $result;
3。单聊请求,如果不提供单聊,3,4两条可用略过了。
这里采用的是,向服务器发送连接请求,然后由对方选择是否接纳。
当然如果不想让用户自己选择连接某个对象,而是由服务器自动配对,这就是当今很流行的路过聊天方式。
其实原理非常简单,例如 luguode.com ,等等,这类聊天非常的多。
简要说明一下由服务器自动配对的做法:
第一步:获取哪些用户仍是单身:
先说明一下状态代码表示:
online表中的status 字段:为0表示用户单身,为3表示用户已经配对。1,2留着有其他用处。
$sql="SELECT * FROM online WHERE sid !='$sid' AND status=0 ";
假如我们取出一个数组:$single_onlines;
下面我们取出一个随机的用户:
srand((double)microtime()*1000000);
// 初始化随机数种子,php 4以后版本据说已不在需要,
// 但很多时候,我还是需要这句才能得到正确的随机数,shit!
$target_index = rand( 0 , count($single_onlines)-1) ; //随机下标
$target_sid = $single_onlines[$target_index]['sid'] ;
$target_ip = $single_onlines[$target_index]['ip'] ;
// 获取到目标的sid 了,下面同时更新用户和我!
$sql="UPDATE online SET status='3', link_sid='$target_sid', link_ip='$target_ip' WHERE sid='$sid' AND ip='$ip' LIMIT 1 ";// 更新我的状态
$sql="UPDATE online SET status='3', link_sid='$sid', link_ip='$ip' WHERE sid='$target_sid' AND ip='$target_ip' LIMIT 1 "; // 更新目标状态
当然了,在更新前,需要做一些简要的判断,例如,我自己是不是已经是3了阿,是表示我已经是和别人建立单聊了,那么就返回一个错误了。
说到这类不知道您发现问题了没?就是,当我没有请求和别人单聊的时候,也可能会被别人啪的连上了。
简单解释一下:例如现在有三个人 A,B,C,我是A,这三个人都是单身,当我向服务器发出请求连接的时候,
这个时候,服务器随机找出了B,而B这个时候并没有向服务器发出连接请求,也会被啪连上了。
所以我们就可以加一个状态判断。例如:status=1表示用户正在向服务器发出连接请求。
0,表示用户什么也没有做,也不想和别人单聊。
而这个时候,就从那些状态为1的用户里面找出一些,随机连接。
如果没有单身了,那么先把用户状态更新为1,返回没有找到的提示。
感觉很罗嗦。所以我就自己设计了一个连接--服务器处理--客户端处理--的这样一个模式。
请求地址:chat.php?ac=linkto
post来的变量:
$linkto=$_POST['linkto'];// 表示要和哪个uid的用户建立连接
如果用户是单身状态,那么连接请求可用,用户的在线列表左边将会出现一个--连接的按钮
这个时候,uid就派上用场了,为什么不用session_id?因为你不可能把用户的session_id都发送给
客户端吧?只有发送uid了,
这个uid可用是随机字母,也可用是随机数字,我这里采用的是6为随机数字。
这里要稍微改动一下,用户第一次访问的情况。
srand((double)microtime()*1000000);
$uid=rand(100000,999999);
$sql="SELECT uid FROM online WHERE uid='$uid'";
while( mysql_fetch_array( mysql_query($sql) )){
$uid=rand(100000,999999);
}// 直到产生一个唯一的uid为止.
循环来验证当前产生的uid是否已经在表中存在了?如果存在,那么继续产生,如果不存在,那就用这个了。
定义一下状态:
0:用户单身
1:用户正在发出连接请求。
2:用户正在被连接请求。
3:用户已经配对。
当连接请求发出的时候,需要判断这样几种情况?
自己状态是:
status=1,
我已经在请求了,这个时候可用根据需要是否允许用户进行多次请求。
一般是允许的。因为如果不允许的话,你发送过去,对方没有即使处理,那么就要一直挂着等了。这样显然不好。当然也可以这么做了。
status=2:
我在被请求,提示错误
status=3:已经成对,提示错误。
第二步,查询对象是否存在,或已经掉线?
$sql=SELECT * FROM online WHERE uid='$linkto' LIMIT 1;
$user2=mysql_fetch_array(mysql_query($sql));
如果不存在$user2,证明已经掉线,返回错误信息。
否则进入下一步:
目标状态:
status=0或1
更新目标用户,返回发送请求成功。
$sql="UPDATE online SET link_uid='$uid2' AND link_sid='$sid2' AND link_ip='$ip2' ";
status=2,
目标已经有人请求,返回请求错误信息。
status=3,目标已经成对,返回错误信息
4.处理连接:
每次刷新信息时候,返回用户自己的信息:
在客户端,用js检测用户状态信息是否为2?
如果为2,则弹出对话框,提示用户是否接收或拒绝连接请求。
接收的时候,仍需要注意几种情况:
自己的状态判断,和目标的状态判断。
最后需要增加一个刷新用户状态,
if($user['status']==3){ // 刷新单点连接
$linksid=$user['linksid'];
$linkip=$user['linkip'];
$sql="SELECT uid FROM online WHERE sid='$linksid' AND ip='$linkip' LIMIT 1";
if(!mysql_fetch_array( mysql_query($sql) ) ){
$sql="UPDATE online SET status='0',info='$info',linkuid='',linksid='',linkip='' WHERE sid='$sid' AND ip='$ip' LIMIT 1";
//更新用户状态,使其重新变为0。
}
}
然后还需要提供一个手动断开连接的处理,这就比较简单啦,直接把自己的状态,和对方状态更新为0,同时清楚掉link_uid....之类的
下面说说前台,基于JQuery的!
前台比较简单。
Chat={};
Chat.get=function(){
$.post('chat.php?ac=get',{'nick':$('#nick').val()},function(data){
// 这里把取到数据 data对象里面的消息追加到聊天窗口。
$.each(data.msg,function(i,msg){
//比较简单就不多写了。
});
//scroll('im'); 这里加一个滚动效果,可用把窗口自动滚动到最底部。
}
setTimeout('Chat.get()',3000);
},'json');
}
function scroll(id){
var scrollTop=document.getElementById(id).scrollHeight - document.getElementById(id).clientHeight >= 0 ? document.getElementById(id).scrollHeight - document.getElementById(id).clientHeight : 0;
document.getElementById(id).scrollTop=scrollTop;
}
其他的请求就略过了,因为比较简单。原理都差不多了。
好了,到这里就基本讲解完了一个ajax聊天室的原理,如果是注册聊天,实行起来会比这个容易些!
具体效果参考:nbajax.com
需要源码的发邮件给我:microji@163.com
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/microji/archive/2009/05/30/4225790.aspx
发表评论
-
overflow hidden 隐藏超出元素
2009-09-10 08:50 2560<!DOCTYPE html PUBLIC " ... -
dwr调用返回List、Set或者Map的java方法
2009-09-08 15:52 27846、调用返回List、Set或者Map的java方法 6.1、 ... -
json-taglib
2009-09-08 15:26 6875(2) json-taglib (http://json-ta ... -
JSON
2009-09-08 15:25 1390JSON作为一种信息的载体伴随着AJAX的红火也越来越得到广大 ... -
动态读取json数据的简单目录树js控件
2009-09-08 14:33 3737经过几天的努力终于完成一个动态读取json数据的简单目录树js ... -
dwr的路径问题
2009-07-16 16:14 1751//dwr 引用util.js,engine.js,beanN ... -
javascript获取FCKeditor内容:
2009-06-27 14:31 1915javascript获取 ... -
DWR实例
2009-06-24 14:05 1587一个非常好的DWR实例 2007-12-02 14: ... -
dwr 使用笔记
2009-06-24 13:53 1156DWR是一个框架,简单的说就是能够在javascript直接调 ... -
dwr converter 配置
2009-06-24 12:19 1844在配置dwr.xml的时候,需要配置 这个元素 DWR帮助我 ... -
dwr与jsp,html页面间参数传递
2009-06-23 11:11 2523DWR 处理各种form表单Select/option,tab ... -
RIA(Rich Interface Applications)
2009-06-22 16:44 1503RIA(Rich Interface Applications ...
相关推荐
Ajax(Asynchronous JavaScript and XML...综上所述,构建一个Ajax聊天室涉及到前端交互设计、Ajax技术、实时通信机制、用户认证、后端处理等多个方面,是一个综合性的Web开发项目,需要对Web技术有深入的理解和实践。
尽管不是AJAX的一部分,但WebSocket可以提供更低延迟、更高效的实时通信,如果聊天室需要实现更多功能,如一对一私聊或群组聊天,WebSocket会是一个理想的选择。 在安全性方面,考虑到聊天室可能面临的XSS(跨站...
本项目“简单Ajax聊天室 实现聊天功能”利用ASP.NET框架和Ajax技术,构建了一个实时、交互性强的在线聊天平台。在这个聊天室中,用户不仅能发送文字消息,还能调整字体样式、颜色,并发送QQ表情,极大地提升了用户...
【基于jQuery的Ajax聊天室程序】是一个典型的Web交互应用,它利用了Ajax技术来实现实时的、无需页面刷新的用户交流。Ajax(Asynchronous JavaScript and XML)是一种在不重新加载整个网页的情况下,能够更新部分网页...
在本项目“AJAX实现的多人聊天室”中,我们利用AJAX的异步特性来实现实时的聊天功能,使得用户可以即时发送和接收消息,提升用户体验。 首先,我们需要理解ASP.NET作为后台框架的角色。ASP.NET是由微软开发的一个...
【Ajax聊天室构建详解】 Ajax(Asynchronous JavaScript and XML)技术是一种在无需刷新整个网页的情况下,能够更新部分网页内容的技术。结合PHP服务器端语言,我们可以创建一个实时、交互性强的在线聊天室。以下是...
最简单的ajax聊天室,适合刚学习ajax的朋友。最简单的ajax聊天室,适合刚学习ajax的朋友。最简单的ajax聊天室,适合刚学习ajax的朋友。最简单的ajax聊天室,适合刚学习ajax的朋友。
**Ajax 聊天室源码详解** Ajax(Asynchronous JavaScript and XML)是一种在无需刷新整个网页的情况下,能够更新部分网页的技术。它通过在后台与服务器进行少量数据交换,使得网页实现异步更新,极大地提升了用户...
【Ajax聊天室】是一个基于Java Web技术实现的简单交互式应用,主要利用了Servlet、JSP和Ajax技术。这个小例子展示了如何通过Ajax实现在不刷新整个页面的情况下更新内容,提供了一个基本的在线聊天功能。 1. **...
### 基于Ajax聊天室的设计与分析 #### 一、引言 近年来,随着互联网技术的迅猛发展,网络应用程序的设计与开发已成为软件开发的重要组成部分。在众多的Web开发工具中,.NET框架以其强大的功能和简便的操作脱颖而出...
【jsp+ajax聊天室】是一种基于JavaServer Pages (JSP) 和 Asynchronous JavaScript and XML (AJAX) 技术实现的在线实时交流平台。JSP是服务器端的技术,用于生成动态网页,而AJAX则是一种在不刷新整个页面的情况下与...
总结来说,"ajax即时聊天程序,无刷新聊天室程序"是运用Ajax技术和相关即时通信策略实现的一个高效、互动的在线聊天平台,它利用JavaScript、XMLHttpRequest对象以及可能的WebSocket或Server-Sent Events技术,确保...
通过阅读源码,我们可以深入理解Ajax聊天室的工作原理,以及如何在实际项目中应用Ajax技术。 **四、学习与进阶** 学习这个Ajax聊天室项目,可以帮助初学者更好地理解Ajax的使用,以及如何结合JavaScript实现动态...
无刷新聊天室的核心理念是利用Ajax(Asynchronous JavaScript and XML)技术,实现在不重新加载整个网页的情况下更新部分页面内容。AJAX允许前端和服务器进行异步通信,这使得用户在发送或接收消息时,无需等待整个...
**Ajax 实现聊天室** Ajax(Asynchronous ...以上就是使用Ajax实现聊天室的基本原理和步骤,它展示了Ajax在构建动态、实时Web应用中的重要性。通过不断学习和实践,你可以创建出更复杂、功能丰富的聊天应用。
本项目是基于JSP技术和AJAX实现的一个在线Web聊天室,它为用户提供了一个实时交流的平台,用户可以在不刷新整个页面的情况下发送和接收消息。这种技术的应用极大地提升了用户体验,因为它允许用户在与其他用户交互时...
总结,构建一个Ajax无刷新的简单聊天室,需要理解Ajax的工作原理,熟练掌握JavaScript DOM操作,以及服务器端的数据处理。通过不断优化和扩展,我们可以创建出更高效、更安全、用户体验更佳的聊天室系统。
【Ajax聊天室】是一个利用Ajax技术实现的实时通信平台,旨在提供一个无需依赖数据库的多人在线聊天环境。在这个系统中,用户可以即时发送和接收消息,与其他用户进行互动,而无需刷新整个网页,大大提升了用户体验。...