WebIM组件设计

其实对于一个WebIM来说,我们一般都几种方式来实现

1.服务器拉送方式:就是客户端主动定时的去服务器端获取信息,一般我们可以通过 Ajax控件+定时器  来实现,优点:实现简单,缺点:服务器承受的压力重

2.服务器推送方式:就是服务器主动将获取到的信息,发送给客户端,Asp.net我们可以通过 IHttpAsyncHandler这个接口来实现,优点:服务器承受的压力小 缺点:服务器 和客户端同时配合编写(js)

3.Flash Socket方式:通过在网页中嵌入Flash,编写Socket程序 通过AS 3.0语言,Socket编程,优点:并发量大,服务器压力小,缺点:浏览器中要支持Flash,加载Flash

下面我实现的是第二种: 

它实现的原理很简单,浏览器向服务器发送一个异步请求,服务器接到请求之后,去内存中查找信息,如果有,就直接处理该请求,如果没有,我们可以把该请求暂存到服务器一段时间,如果在该时间段内,有符合自己信息的到来,我们就直接处理,否则我们要丢掉该请求(其实请求丢掉之后,如果客户端任然在线,客户端会重新在次发送请求,就像是心跳包)

Chat聊天异步处理程序
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Web;
namespace DNCCFrameWork.Chat
{
    
/// <summary>
    
/// Chat聊天异步处理程序
    
/// </summary>
    public class ChatAsyncHandler : IHttpAsyncHandler
    {

        
//接受客户端请求
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
        {
            System.IO.Stream stream 
= context.Request.InputStream;
            
byte[] b = ReadDate(stream);
            
string str = context.Server.UrlDecode(context.Request.ContentEncoding.GetString(b));
            Hashtable ht 
= SplitRequestPara(str);
            
string type = ht["type"as string;
            
string message = ht["content"as string;
            
string sendUser = ht["sendusers"as string;
            
string receiveUser = ht["receiveusers"as string;
            IChatMessage chatMessage 
= new ChatMessage();
            chatMessage.Type 
= type;
            chatMessage.Content 
= message;
            chatMessage.SendUser 
= sendUser;
            chatMessage.ReceiveUser 
= receiveUser;
            ChatAsyncResult chatAsyncResult 
= new ChatAsyncResult(context, cb, extraData, chatMessage);
            IChat chat 
= new ChatDefault();

            chat.IM(chatAsyncResult);

            
return chatAsyncResult;

        }

        
#region 读流中的全部数据
        
private byte[] ReadDate(System.IO.Stream stream)
        {
            
byte[] buff = new byte[stream.Length];
            
int curOffset = 0;
            
int totalCount = 0;
            
int readCount = 0;
            
int size = buff.Length;
            
while (totalCount < size)
            {
                
int exceptSize = size - totalCount;
                readCount 
= stream.Read(buff, curOffset, exceptSize);
                curOffset 
+= readCount;
                totalCount 
+= readCount;
            }
            
return buff;
        }
        
#endregion

        
#region 分离请求数据
        
private Hashtable SplitRequestPara(string str)
        {
            Hashtable ht 
= new Hashtable();
            
string[] str1 = str.Split(new char[] { '&' });
            
foreach (string temp in str1)
            {
                
string[] str2 = temp.Split(new char[] { '=' });
                
if (str2.Length == 2)
                {
                    
if (!ht.ContainsKey(str2[0].ToLower().ToString()))
                    {
                        ht.Add(str2[
0].ToLower().ToString(), str2[1].ToString());
                    }
                }
            }
            
return ht;

        }
        
#endregion

        
public void EndProcessRequest(IAsyncResult result)
        {

        }

        
#region IHttpHandler接口
        
public bool IsReusable
        {
            
get { return false; }
        }
        
public void ProcessRequest(HttpContext context)
        {

        }
        
#endregion

        
#region 请求检测
        
private bool RequestCheck(IChatMessage cm)
        {
            
bool status = true;
            
if (string.IsNullOrEmpty(cm.Type))
            {
                status 
= false;

            }
            
else
            {
                
try
                {
                    cm.Type 
= Common.Security.CryptoTextBase.ProcessText(cm.Type, false);
                }
                
catch
                {
                    status 
= false;
                }
            }
            
if (string.IsNullOrEmpty(cm.SendUser))
            {
                status 
= false;
            }
            
if (string.IsNullOrEmpty(cm.ReceiveUser))
            {
                status 
= false;
            }
            
return status;
        }
        
#endregion

    }
}

 

 

消息处理中心
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace DNCCFrameWork.Chat
{
    
public class ChatMessageDispatcherDefault : IChatMessageDispatcher
    {
        
private  IChatMessageSendStrategy m_chatMessageSendStrategy = new ChatMessageSendStrategyDefault();
        
private  IChatMessageHook m_chatMessageHook = new ChatMessageHookDefault();
        
private  IChatMessageSpy m_chatMessageSpy = new ChatMessageSpyDefault();
        
private  IChatMessageDeal m_chatMessageDeal;
        
private  IChatMessageManager m_chatMessageManager = new ChatMessageManagerDefault();
        
private  IChatRequestManager m_chatRequestManager = new ChatRequestManagerDefault();
        
private static object o = new object();
        
public  void Dispatcher(ChatAsyncResult chatAsyncResult)
        {
            ChatAsyncResult car 
= Receive(chatAsyncResult);//接受请求
            m_chatMessageDeal = ChatMessageDealFactory.GetChatMessageDeal(car);//获取请求对应的处理器
            if (m_chatMessageDeal != null)
            {
                m_chatMessageDeal.Deal(car);
//处理器处理消息,保存消息,或保存请求    
                lock (o)
                {
                    DispatcherSend();
//发送消息 
                }
            }
        }
        
public void DispatcherSend()
        {
            
int count = m_chatRequestManager.Count();
            
for (int i = 0; i < count; i++)
            {
                IChatRequest chatRequest 
= m_chatRequestManager.Pop();
                
if (chatRequest != null)
                {
                    Dictionary
<stringstring> dic = new Dictionary<stringstring>();
                    dic.Add(
"SendUser", chatRequest.ChatAsyncResult.ChatMessage.SendUser);
                    dic.Add(
"ReceiveUser", chatRequest.ChatAsyncResult.ChatMessage.ReceiveUser);
                    dic.Add(
"Type", chatRequest.ChatAsyncResult.ChatMessage.Type);
                    IList lt 
= m_chatMessageManager.Find(dic);
                    
if (lt.Count <= 0)
                    {
                        TimeSpan ts 
= DateTime.Now - chatRequest.ChatAsyncResult.ChatMessage.CreateDate;
                        
if (ts.TotalSeconds < 600)//请求超时系统丢弃请求
                        {
                            m_chatRequestManager.Push(chatRequest);
                        }
                    }
                    
else
                    {
                        IList temp 
= new ArrayList(); ;
                        
foreach (IChatMessage chatMessage in lt)
                        {
                            IChatMessage cm 
= Send(chatMessage);
                            temp.Add(cm);
//发送消息前   

                        }
                        StringBuilder sb 
= new StringBuilder();
                        
for (int j = 0; j < temp.Count; j++)
                        {
                            IChatMessage cha 
= temp[j] as IChatMessage;
                            sb.Append(cha.ToString()).Append(
"<br/>");
                        }
                        chatRequest.ChatAsyncResult.ChatMessage.Content 
= sb.ToString();
                        m_chatMessageSendStrategy.Send(
null, chatRequest);
                    }
                }

            }
        }
        
public  IChatMessage Send(IChatMessage chatAsyncResult)
        {
            IChatMessage car 
= m_chatMessageHook.Send(chatAsyncResult);
            car 
= m_chatMessageSpy.Send(car);
            
return car;
        }
        
public  ChatAsyncResult Receive(ChatAsyncResult chatAsyncResult)
        {
            ChatAsyncResult car 
= m_chatMessageHook.Receive(chatAsyncResult);
            car 
= m_chatMessageSpy.Receive(car);
            
return car;
        }
    }
}

 

消息内存存储介质
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Configuration;
namespace DNCCFrameWork.Chat
{
    
public class ChatMessageStoreageMemory : IChatMessageStorage
    {
        
private static Dictionary<string, LinkedList<IChatMessage>> m_SendUserReceiveChatMessage = new Dictionary<string, LinkedList<IChatMessage>>();
        
private static ChatMessageStoreageDataBase db = new ChatMessageStoreageDataBase();
        
private static Dictionary<stringobject> m_Lock = new Dictionary<stringobject>();
        
private static int m_ChatGroupALiveTime = 5;
        
private static int m_ChatMessageGC = 5;
        
private static DateTime m_LastChatMessageGC = DateTime.Now;
        
private static System.Timers.Timer GC = new System.Timers.Timer(m_ChatMessageGC * 60 * 1000);
        
static ChatMessageStoreageMemory()
        {
            IList lt 
= db.Find();//获取数据库中为发送信息
            foreach (IChatMessage chatMessage in lt)
            {
                BackChatMessage(chatMessage);
            }
            
int.TryParse(ConfigurationManager.AppSettings["ChatGroupALiveTime"], out m_ChatGroupALiveTime);
            
int.TryParse(ConfigurationManager.AppSettings["ChatMessageGC"], out m_ChatMessageGC);
            GC.Interval 
= m_ChatMessageGC * 60 * 1000;
            GC.Elapsed 
+= new System.Timers.ElapsedEventHandler(GC_Elapsed);
            GC.Enabled 
= true;
            GC.Start();
        }

        
static void GC_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            ChatMessageGC();
        }
        
private static void BackChatMessage(IChatMessage chatMessage)
        {
            
string key = "";
            
string key2 = "";
            
if (chatMessage.Type.Equals(ChatType.oneTonoeSend))
            {
                key 
= chatMessage.SendUser + "<-->" + chatMessage.ReceiveUser;
                key2 
= chatMessage.ReceiveUser + "<-->" + chatMessage.SendUser;
            }
            
if (chatMessage.Type.Equals(ChatType.manyTomanySend))
            {
                key 
= key2 = chatMessage.ReceiveUser;
            }
            
if (!m_SendUserReceiveChatMessage.ContainsKey(key) || !m_SendUserReceiveChatMessage.ContainsKey(key2))
            {
                
lock (m_SendUserReceiveChatMessage)
                {
                    
if (!m_SendUserReceiveChatMessage.ContainsKey(key) && !m_SendUserReceiveChatMessage.ContainsKey(key2))
                    {
                        m_SendUserReceiveChatMessage.Add(key, 
new LinkedList<IChatMessage>());
                        m_Lock.Add(key, 
new object());
                    }
                }

            }
            
if (m_SendUserReceiveChatMessage.ContainsKey(key))
            {
                
lock (m_Lock[key])
                {
                    
if (m_SendUserReceiveChatMessage.ContainsKey(key))
                    {
                        
if (m_SendUserReceiveChatMessage[key].Count >= 1)
                        {
                            
bool status = false;
                            IChatMessage temp 
= null;
                            
foreach (IChatMessage cm in m_SendUserReceiveChatMessage[key])
                            {
                                
if (cm.CreateDate > chatMessage.CreateDate)
                                {
                                    temp 
= cm;
                                    status 
= truebreak;
                                }
                            }
                            
if (status)
                            {
                                m_SendUserReceiveChatMessage[key].AddBefore(m_SendUserReceiveChatMessage[key].Find(temp), chatMessage);
                            }
                            
if (!status)
                            {
                                m_SendUserReceiveChatMessage[key].AddLast(chatMessage);
                            }
                        }
                        
else
                        {
                            m_SendUserReceiveChatMessage[key].AddFirst(chatMessage);
                        }
                    }
                }
            }
            
else
            {
                
lock (m_Lock[key2])
                {
                    
if (m_SendUserReceiveChatMessage.ContainsKey(key2))
                    {
                        
if (m_SendUserReceiveChatMessage[key2].Count >= 1)
                        {
                            
bool status = false;
                            IChatMessage temp 
= null;
                            
foreach (IChatMessage cm in m_SendUserReceiveChatMessage[key2])
                            {
                                
if (cm.CreateDate > chatMessage.CreateDate)
                                {
                                    temp 
= cm;
                                    status 
= true;
                                    
break;
                                }
                            }
                            
if (status)
                            {
                                m_SendUserReceiveChatMessage[key2].AddBefore(m_SendUserReceiveChatMessage[key2].Find(temp), chatMessage);
                            }
                            
if (!status)
                            {
                                m_SendUserReceiveChatMessage[key2].AddLast(chatMessage);
                            }
                        }
                        
else
                        {
                            m_SendUserReceiveChatMessage[key2].AddFirst(chatMessage);
                        }
                    }
                }
            }
        }
        
public void Add(IChatMessage chatMessage)
        {
            
string key = "";
            
string key2 = "";
            
if (chatMessage.Type.Equals(ChatType.oneTonoeSend))
            {
                key 
= chatMessage.SendUser + "<-->" + chatMessage.ReceiveUser;
                key2 
= chatMessage.ReceiveUser + "<-->" + chatMessage.SendUser;
            }
            
if (chatMessage.Type.Equals(ChatType.manyTomanySend))
            {
                key 
= key2 = chatMessage.ReceiveUser;
            }
            
if (!m_SendUserReceiveChatMessage.ContainsKey(key) || !m_SendUserReceiveChatMessage.ContainsKey(key2))
            {
                
lock (m_SendUserReceiveChatMessage)
                {
                    
if (!m_SendUserReceiveChatMessage.ContainsKey(key) && !m_SendUserReceiveChatMessage.ContainsKey(key2))
                    {
                        m_SendUserReceiveChatMessage.Add(key, 
new LinkedList<IChatMessage>());
                        m_Lock.Add(key, 
new object());
                    }
                }

            }
            
if (m_SendUserReceiveChatMessage.ContainsKey(key))
            {
                
lock (m_Lock[key])
                {
                    
if (m_SendUserReceiveChatMessage.ContainsKey(key))
                    {
                        
if (m_SendUserReceiveChatMessage[key].Count >= 1)
                        {
                            
bool status = false;
                            IChatMessage temp 
= null;
                            
foreach (IChatMessage cm in m_SendUserReceiveChatMessage[key])
                            {
                                
if (cm.CreateDate > chatMessage.CreateDate)
                                {
                                    temp 
= cm;
                                    status 
= truebreak;
                                }
                            }
                            
if (status)
                            {
                                m_SendUserReceiveChatMessage[key].AddBefore(m_SendUserReceiveChatMessage[key].Find(temp), chatMessage);
                            }
                            
if (!status)
                            {
                                m_SendUserReceiveChatMessage[key].AddLast(chatMessage);
                            }
                        }
                        
else
                        {
                            m_SendUserReceiveChatMessage[key].AddFirst(chatMessage);
                        }
                        cb c 
= new cb(db.Add);
                        c.BeginInvoke(chatMessage, 
nullnull);//异步写入数据库 
                    }
                }
            }
            
else
            {
                
lock (m_Lock[key2])
                {
                    
if (m_SendUserReceiveChatMessage.ContainsKey(key2))
                    {
                        
if (m_SendUserReceiveChatMessage[key2].Count >= 1)
                        {
                            
bool status = false;
                            IChatMessage temp 
= null;
                            
foreach (IChatMessage cm in m_SendUserReceiveChatMessage[key2])
                            {
                                
if (cm.CreateDate > chatMessage.CreateDate)
                                {
                                    temp 
= cm;
                                    status 
= true;
                                    
break;
                                }
                            }
                            
if (status)
                            {
                                m_SendUserReceiveChatMessage[key2].AddBefore(m_SendUserReceiveChatMessage[key2].Find(temp), chatMessage);
                            }
                            
if (!status)
                            {
                                m_SendUserReceiveChatMessage[key2].AddLast(chatMessage);
                            }
                        }
                        
else
                        {
                            m_SendUserReceiveChatMessage[key2].AddFirst(chatMessage);
                        }
                        cb c 
= new cb(db.Add);
                        c.BeginInvoke(chatMessage, 
nullnull);//写入数据库 
                    }
                }
            }
        }
        
public IList Find(Dictionary<stringstring> dic)
        {

            
string key = "";
            
if (dic["Type"].Equals(ChatType.oneTooneReceive))
            {
                key 
= dic["SendUser"+ "<-->" + dic["ReceiveUser"];
            }
            
if (dic["Type"].Equals(ChatType.manyTomanyReceive))
            {
                key 
= dic["ReceiveUser"];
            }
            IList lt 
= new ArrayList();

            
if (m_SendUserReceiveChatMessage.ContainsKey(key))
            {
                
lock (m_Lock[key])
                {
                    
if (m_SendUserReceiveChatMessage.ContainsKey(key))
                    {
                        
foreach (IChatMessage chatMessage in m_SendUserReceiveChatMessage[key])
                        {
                            
if (!chatMessage.IsSend(dic["SendUser"]) && !chatMessage.IsOver)
                            {
                                chatMessage.SendUserList.Add(dic[
"SendUser"]);
                                chatMessage.ReadDateList.Add(DateTime.Now.ToString());
                                ChatMessageOverCheck(chatMessage);
                                cb c 
= new cb(db.Update);
                                c.BeginInvoke(chatMessage.Clone(), 
nullnull);//异步更新数据库     
                                lt.Add(chatMessage);
                            }
                        }
                    }
                }
            }
            
else
            {
                
if (dic["Type"].Equals(ChatType.oneTooneReceive))
                {
                    key 
= dic["ReceiveUser"+ "<-->" + dic["SendUser"];
                }
                
if (dic["Type"].Equals(ChatType.manyTomanyReceive))
                {
                    key 
= dic["ReceiveUser"];
                }
                
if (m_SendUserReceiveChatMessage.ContainsKey(key))
                {
                    
lock (m_Lock[key])
                    {
                        
if (m_SendUserReceiveChatMessage.ContainsKey(key))
                        {
                            
foreach (IChatMessage chatMessage in m_SendUserReceiveChatMessage[key])
                            {
                                
if (!chatMessage.IsSend(dic["SendUser"]) && !chatMessage.IsOver)
                                {
                                    chatMessage.SendUserList.Add(dic[
"SendUser"]);
                                    chatMessage.ReadDateList.Add(DateTime.Now.ToString());
                                    ChatMessageOverCheck(chatMessage);
                                    cb c 
= new cb(db.Update);
                                    c.BeginInvoke(chatMessage.Clone(), 
nullnull);//异步更新数据库                                
                                    lt.Add(chatMessage);
                                }
                            }
                        }
                    }
                }
            }
            
return lt;

        }
        
public void Clear(Dictionary<stringstring> dic)
        {
        }
        
public void Clear(IList lt)
        {

        }

        
#region 定时内存清理
        
private static void ChatMessageGC()
        {
            
foreach (KeyValuePair<string, LinkedList<IChatMessage>> kvp in m_SendUserReceiveChatMessage)
            {
                
if (kvp.Value.Count > 0)
                {
                    
lock (m_Lock[kvp.Key])
                    {
                        
if (kvp.Value.Count > 0)
                        {
                            IList lt 
= new ArrayList();
                            
foreach (IChatMessage cm in kvp.Value)
                            {
                                
if (!cm.IsOver)
                                {
                                    ChatMessageOverCheck(cm);
                                }
                                
if (cm.IsOver)
                                {
                                    lt.Add(cm);
                                }
                            }
                            
foreach (IChatMessage cm in lt)
                            {
                                kvp.Value.Remove(cm);
                                cb b 
= new cb(db.Add2);
                                b.BeginInvoke(cm.Clone(), 
nullnull);//进入历史数据库
                            }
                        }
                    }
                }


            }

        }
        
#endregion

        
#region 消息完成结束检测
        
private static void ChatMessageOverCheck(IChatMessage cm)
        {
            
if (cm.Type.Equals(ChatType.oneTonoeSend) && cm.SendUserList.Count >= 2)
            {
                cm.OverDate 
= DateTime.Now;
                cm.IsOver 
= true;
            }
            
if (cm.Type.Equals(ChatType.manyTomanySend))
            {
                TimeSpan ts 
= DateTime.Now - cm.CreateDate;
                
if (ts.TotalMinutes > m_ChatGroupALiveTime)
                {
                    cm.OverDate 
= DateTime.Now;
                    cm.IsOver 
= true;
                }
            }
        }
        
#endregion
    }
    
public delegate void cb(IChatMessage chatMessage);
}

 

所有的消息都先存储在内存中,然后异步更新到数据库中(相当于内存快照,一旦应用程序重启,没有被处理完过的消息,将重新加载到内存中),一旦消息被处理过(一对一聊天,双方都接受到)则消息标记为已处理过,消息就会从内存中清除,同时被异步更新到历史库表中 

 JS部分:

客户端异步发请求

    
<script src="../Js/jquery-1.4.3.js" type="text/javascript" language="javascript"></script>

    
<script type="text/javascript">  
        $(document).ready(function () {

            function send() 
            {
                var str
=$.trim($("#ctl00_ContentPlaceHolder1_tbMSGInput").val());             
                var sendUser 
= $.trim('<% = MyUid %>');
                var receiveUser 
= $.trim('<% = ToUID %>');
                
if(sendUser.length<1&&receive.length<1)
                {
                    
return;
                }
                
if(str.length>1)
                {        
                    $.ajax({
                        type: 
"post",
                        url: 
"IM.aspx",
                        timeout:
30000,    
                        data:{ content: str, type: 
"0", sendUsers: sendUser, receiveUsers: receiveUser } ,
                        dataType:
"html",
                        success:   function (data, status) 
                                   {    
                                      
if(data!="发送成功")
                                        {
                                             var result 
= $("#ctl00_ContentPlaceHolder1_lbChatShow");
                                             result.html(result.html()
+data+"<br/>");    
                                        }
                                     
else
                                        {                  
                                              $(
"#ctl00_ContentPlaceHolder1_tbMSGInput").val("");
                                        }
           
                                    },          
                      error: function(XMLHttpRequest, textStatus, errorThrown)
                                {        
                                      var result 
= $("#ctl00_ContentPlaceHolder1_lbChatShow");
                                      result.html(result.html()
+textStatus+"<br/>");                                        
                                }
                       });
                        $(
"#ctl00_ContentPlaceHolder1_tbMSGInput").val("");
                }         
            }

            function wait() 
                {
                    var sendUser 
= $.trim('<% = MyUid %>');
                    var receiveUser 
= $.trim('<% = ToUID %>');
                    
if(sendUser.length<1&&receive.length<1)
                      {
                               
return;
                      }        
                    $.ajax({
                        type: 
"post",
                        url: 
"IM.aspx",
                        timeout:
30000,    
                        data:{ content: 
"", type: "1", sendUsers: sendUser, receiveUsers: receiveUser } ,
                        dataType:
"html",
                        success:function (data, status) 
                        {
                            var result 
= $("#ctl00_ContentPlaceHolder1_lbChatShow");
                            result.html(result.html()
+data);
                            var outerHeight 
= $("#ctl00_ContentPlaceHolder1_lbChatShow").outerHeight(); 
                            var innerHeight 
= $("#div_Message").innerHeight();
                            var scrollTop 
= outerHeight - innerHeight + 20;
                             $(
"#div_Message").scrollTop(scrollTop);
                             wait();
                        },          
                        error: function(XMLHttpRequest, textStatus, errorThrown)
                        {    
                            wait();
                        }
                        });                 
              };            

            
//初始化连接
             wait();
            $(
"#btnSend").click(function () { send(); });         
            $(
"#ctl00_ContentPlaceHolder1_tbMSGInput").keypress(function (event) {
                
if (event.keyCode == 13) {
                    send();
                }
            });
        });
    
</script>

 

 部署方式:

在Web.config httpHandlers中加入即可

 <add path="IM.aspx" type="DNCCFrameWork.Chat.ChatAsyncHandler" verb="POST,Get"/>

posted on 2011-01-27 17:58  永不满足  阅读(2199)  评论(13编辑  收藏  举报

导航