基于Ajax的即时聊天实现(客户端)

     腾讯的网页即时聊天出现了一段时日了,开始以为腾讯是使用flash xmlsocket来建立服务器“推”消息到客户端的,但是通过对客户端代码的分析,以及使用httpwatch监视,发现也是使用按刷新率来“拉”消息。为什么不使用flash做接口呢?参考了许多网上的例子,以及各方面的反应,估计有以下几点
个人观点,欢迎指证)。我不是flash程序员
  1. flash与浏览器JS脚本交互效率不高,经常出现无响应的假死状态.
  2. flash xmlsocket使用socket协议来通信,这需要服务器端socket监听程序来支持。
    flash的安全性要求连接的主机必须在同域或配置安全性许可文件(security.xml)?,种种实现起来还是较复杂的。我不是不推行这种方式,但是对于我们这些一直没有真正包含AS脚本编程经验的同志,实现起来有点难度。
什么是ajax?大家可以去百度或Google查询下怎么定义的。总结一下就几个关键词语:异步回调,后台请求
现在网上到处都是ajax技术的文章。其实说的再多,反而让你觉得神秘莫测。
一,原理分析 
目前的即时聊天技术实现,使用按设定的时间来刷新获取服务器的新消息,通常使用反复查询数据库来实现。但是这种效率和服务器资源消耗率都不是很理想。
  如果我们在服务器内存,设定某种消息标识机制。用来标识某个客户端是否有新消息,这比反复查询数据库的效率要高的多。但是消息格式是怎样的呢?我们一步一  步来分析和实现一下。和各位朋友来一同探讨。
  这是我目前的项目所包含的一个聊天模块:
 
  聊天窗口很简单,上面是内容显示区,下面是消息发送区。客户端使用javascript(jquery框架)来处理消息的发送和接收。
  如果构建这样的窗口只需要一些css布局方面的知识就足够了。我们只讲核心的实现方式
  提示:jquery框架封装了很多ajax相关的方法以及方便对DOM操作的一系列函数。
  客户端聊天代码: 
chatplugin.js


 二。消息结构

上面的客户端代码,重点在于包装消息请求,以及对服务器端响应的JSON数据进行处理。

Async函数是封装的AJAX请求函数

Async(请求地址,请求参数json结构,响应函数,内容响应格式,发送方式)

如果你对jquery有了解,其实这和JQUERYajax发送请求方式非常相似,这里进一步封装只是稍微方便一些。

1.发送消息(请求):

 1 function sendMessage(targetid,content){
 2 
 3     var eco=encode64(content);
 4 
 5     Async('chat/send/',{
 6 
 7             target:targetid,
 8 
 9             uid:User.id,
10 
11             m:eco
12 
13            },function(r){
14 
15                   var t=date2str(new Date());
16 
17                   if(!r){showError('与服务器通讯发生错误。',t);return false;}
18 
19                   if(!r.st){showError(r.err,t);return false;}
20 
21                   addMessage(User.nick,User.id,content,t,r.dbid,true);//添加消息到聊天窗口
22 
23                   clearhtml();//清空发送消息框的内容
24 
25                   $("#sendbutton").css({disabled:false});
26 
27            },'json','POST');
28 
29 }

解释:

实际请求url /chat/send.aspx         上面的url使用urlrewrite

sendMessage(targetid,content) 函数

targetid:目标ID(可以是用户,聊天室ID) 在服务器端代码里会解释这个ID

uid:用户ID

m:使用BASE64客户端加密的消息内容

function(r){//json响应回调

       ….//这个AJAX请求发送后服务器的响应处理

}

服务器JSON消息响应:

{

st:true,

dbid:123,

err:”…..”

}

解释:

st:消息发送是否成功(true/false),dbid:消息所存储在数据库中的IDerr: 如果出现错误,服务器返回的错误信息。如果成功则留空字符串。

 

2.服务器消息的获取:

对于消息的获取,我们使用setTimeout函数启动一个“线程”隔5s去服务器端请求一次。然后处理服务器响应的内容。这里的内容可能是有新消息,或者没有任何新内容。

 1 function getMessage(userid,targetid){
 2     //changecaption(__lastMessageTime);
 3     if(__closed){
 4         $("#loading").show();
 5          return false;
 6      }
 7     Async('chat/get/',{
 8         uid:userid,
 9         target:targetid,
10         last:(typeof __lastMessageTime=='undefined')?'':__lastMessageTime
11         },function(r){
12             var t=date2str(new Date());
13             if(!r){showError('网络错误或数据传输失败。',t);return false;}
14             if(!r.st){showError(r.err,t);return false;}
15             var mtime='';
16             if(r.datas.length>0){
17                 //按messageid顺序排序
18                 r.datas=r.datas.sort(function(a,b){
19                     return a.mid-b.mid;
20                 });
21                 $.each(r.datas,function(i,n){
22                     var b=true;
23                     if(__lastMessageTime==''){
24                         if($("#msg"+n.mid).length!=0){
25                             b=false;
26                         }
27                     }
28                     if(b)addMessage(n.uname,n.uid,decode64(n.m),n.t,n.mid,n.uid==User.id);
29                     mtime=n.t;
30                 });
31                 if(mtime!='')
32                  __lastMessageTime=mtime;
33                 flashMessage();
34             }
35             //清除LOADING
36             if(!$("#loading").is(":hidden")){ __loading=false;$("#loading").hide();}
37             setTimeout(function(){getMessage(User.id,__targetid);},__constTime)
38         },'json','GET');
39 }

上面的getMessage(userid,targetid)函数 参数userid:用户IDtargetid:目标ID

请求服务器地址:chat/get.aspx

发送到服务器端的参数:

uid:userid, //用户id

target:targetid,//目标ID

last:(typeof __lastMessageTime=='undefined')?'':__lastMessageTime //最后消息接收时间(全局变量)如果第一次请求消息,则为空。

请求发送后服务器返回JSON消息格式数据

 

{

       st: true,

datas:[

{…},

{…},

{…}

]

}

服务器只返回非自身发送的消息,换句话说就是别人给我发送的消息,才返回消息数据。

同样:st表示消息的失败标志位:true表成功,false表失败

Datas:是一个数组。包含一条条的消息对象,里面的元素同样是json对象

{…}的最终结构:

 {

 mid:消息ID,

 uid:发送者用户id,

 uname:发送者用户名,

 tid:目标ID,

 m:’消息内容(使用base64加密,须解码)’,

 t:’消息发送时间

}

一个标准的消息返回示例:

{

 st:true.

datas:[

{

mid:1,uid:2,uname=’用户A’,tid:1,m:”--encode---”,t:’2009-8-7 21:38:20’

},

{

mid:2,uid:3,uname=’用户B’,tid:1,m:”---encode--”,t:’2009-8-7 21:38:22’

},

{

mid:3,uid:2,uname=’用户A’,tid:1,m:”--encode---”,t:’2009-8-7 21:38:33’

}

]

}

对服务器响应的消息,除了排序并添加到聊天内容框,还有一个比较重要的变量t变量

对于成功有效的消息,这个t时间变量表明了我最后一条接收的消息时间是t,然后将它存储在__lastMessageTime=t;全局变量中,在下次获取新消息的时候会加上这个变量作为请求参数,服务器端判断这个请求,检查内存application变量或asp.netHttpApplication静态类变量(也叫服务器全局变量)中有没有大于这个时间的消息,并且发送者不是我自己。

服务器端处理代码将在下一节提供。

在消息处理后继续隔__constTime所设定的时间,继续请求服务器端获取新内容,达到一个循环。

setTimeout(function(){getMessage(User.id,__targetid);},__constTime)

如果获取消息失败会自动停止再次请求(这里可以修改成,失败继续模式)

 

当然,安全性方面我们需要过滤客户端的一些非法代码或攻击脚本,提高服务器安全性。这里可以使用正则表达式进行过滤。具体代码在稍候提供的压缩包中。

 

客户端的消息发送格式和服务器的响应格式大体就这样子,下一篇日志中,我会给大家提供服务器端的实现,以及数据库方面的内容。

《基于AJAX的即时聊天(2)-服务器端》


posted on 2009-08-07 13:47  Teddy110  阅读(1205)  评论(3)    收藏  举报

导航