zoukankan      html  css  js  c++  java
  • WebIM组件设计<转>

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

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

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

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

    下面我实现的是第二种: 

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

    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
    <string, string> dic = new Dictionary<string, string>();
    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<string, object> m_Lock = new Dictionary<string, object>();
    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
    = true; break;
    }
    }
    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
    = true; break;
    }
    }
    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,
    null, null);//异步写入数据库
    }
    }
    }
    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,
    null, null);//写入数据库
    }
    }
    }
    }
    public IList Find(Dictionary<string, string> 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(),
    null, null);//异步更新数据库
    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(),
    null, null);//异步更新数据库
    lt.Add(chatMessage);
    }
    }
    }
    }
    }
    }
    return lt;

    }
    public void Clear(Dictionary<string, string> 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(),
    null, null);//进入历史数据库
    }
    }
    }
    }


    }

    }
    #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"/>

  • 相关阅读:
    DB开发之oracle存储过程
    DB开发之mysql
    DB开发之oracle
    DB开发之postgresql
    Object-C开发之instancetype和id关键字
    Linux 学习笔记
    Java开发之JDK配置
    Android开发在路上:少去踩坑,多走捷径
    C/C++之Qt正则表达式
    Linux 安全配置指南
  • 原文地址:https://www.cnblogs.com/wenjl520/p/1985674.html
Copyright © 2011-2022 走看看