一步一步打造WebIM(1) (转载)
原出处:http://www.cnblogs.com/lucc/archive/2010/04/24/1719397.html
作者:http://www.cnblogs.com/lucc/
之前笔者发布的云翔在线软件平台中已经包含了一个功能相对比较齐全的WebIM,这个系列的文章就是介绍如何开发出功能类似的WebIM,在文章开始前,先介绍一下相关的技术:
1.Comet
Comet 是一种新的 Web 应用架构。基于这种架构开发的应用中,服务器端会主动以异步的方式向客户端程序推送数据,而不需要客户端显式的发出请求。Comet 架构非常适合事件驱动的 Web 应用,以及对交互性和实时性要求很强的应用,如股票交易行情分析、聊天室和 Web 版在线游戏等。
在.NET要实现Comet就要用到IHttpAsyncHandler,在开始阅读文章前,建议先了解一下IHttpAsyncHandler。
2.Lesktop
Lesktop是一款用于开发RIA网站的开源JS界面库,Lesktop提供了一个功能强大的可视化开发工具帮助您快速的开发RIA网站。这个系列介绍的WebIM的前台UI将使用Lesktop来开发。
接下来,将开始今天的主题,开发一个简单的WebIM,这个WebIM将使用Comet技术,从而避免在客户端和服务端轮询,提高WebIM的性能(目前主要实现能够聊天,其他功能会在以后不断完善)。客户端界面在这就不详细介绍了,用Lesktop拖拖控件就可以了,效果如下:
1.基本思路
Comet便是指服务器推技术。它的实现方式是在浏览器与服务器之间建立一个长连接,待获得消息之后立即返回。否则持续等待,直至超时。客户端得到消息或超时之后,又会立即建立另一个长连接。Comet技术的最大优势,自然就是很高的即使性。在.NET中实现这种方式并不困难,用IHttpAsyncHandler即可。
接收消息的流程:
发送消息流程:
发送消息和添加监听器将由一个类型为MessageManagement对象来负责,
添加监听器代码如下:
/// <summary>/// 添加消息监听器,如果查找到符合监听器条件的消息,返回false,此时不会添加监听器/// 如果没有查找到符合监听器条件的消息,返回true,此时监听器将被添加到m_Listeners中/// </summary>public bool AddListener(String receiver, String sender, Nullable<DateTime> from, WebIM_AsyncResult asynResult){ MessageListener listener = new MessageListener(receiver, sender, from, asynResult); lock (m_Lock) { if (!m_Listeners.ContainsKey(receiver)) { m_Listeners.Add(receiver, new List<MessageListener>()); } List<MessageListener> listeners = m_Listeners[receiver] as List<MessageListener>; //查找消息 List<Message> messages = Find(receiver, sender, from); if (messages.Count == 0) { //插入监听器 listeners.Add(listener); } else { //发送消息 listener.Send(messages); } return messages.Count == 0; }}
发送消息代码如下:
/// <summary>/// 插入新的消息,插入消息后将查询m_Listeners中是否有符合条件的监听器,如存在,同时将消息发送出去/// </summary>public Message NewMessage(String receiver, String sender, DateTime createdTime, String content){ lock (m_Lock) { Message message = new Message(sender, receiver, content, createdTime, ++m_MaxKey); SQLiteCommand cmd = new SQLiteCommand( "insert into Message (Receiver,Sender,Content,CreatedTime,Key) values (?,?,?,?,?)", m_Conn ); cmd.Parameters.Add("Receiver", DbType.String).Value = message.Receiver; cmd.Parameters.Add("Sender", DbType.String).Value = message.Sender; cmd.Parameters.Add("Content", DbType.String).Value = message.Content; cmd.Parameters.Add("CreatedTime", DbType.DateTime).Value = message.CreatedTime; cmd.Parameters.Add("Key", DbType.Int64).Value = message.Key; cmd.ExecuteNonQuery(); List<Message> messages = new List<Message>(); messages.Add(message); if (m_Listeners.ContainsKey(receiver)) { List<MessageListener> listeners = m_Listeners[receiver] as List<MessageListener>; List<MessageListener> removeListeners = new List<MessageListener>(); foreach (MessageListener listener in listeners) { if ((listener.Sender == "*" || String.Compare(listener.Sender, sender, true) == 0) && (listener.From == null || message.CreatedTime > listener.From)) { listener.Send(messages); removeListeners.Add(listener); System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(listener.Complete)); } } foreach (MessageListener listener in removeListeners) { //移除监听器 listeners.Remove(listener); } } return message; }}
2.使用IHttpAsyncHandler实现Comet
IHttpAsyncHandler的介绍可以查阅下msdn,以下是接收消息的源代码,主要是重写BeginProcessRequest和EndProcessRequest:
public class WebIM_ReceiveHandler : IHttpAsyncHandler{ public WebIM_ReceiveHandler() { } HttpContext m_Context = null; IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) { m_Context = context; System.IO.Stream inputStream = context.Request.InputStream; Byte[] buffer = new Byte[inputStream.Length]; inputStream.Read(buffer, 0, (int)inputStream.Length); string content = context.Request.ContentEncoding.GetString(buffer); Hashtable data = Utility.ParseJson(content) as Hashtable; WebIM_AsyncResult asyncResult = new WebIM_AsyncResult(cb, extraData); Nullable<DateTime> from = data.ContainsKey("From") ? new Nullable<DateTime>((DateTime)data["From"]) : null; if (!MessageManagement.Instance.AddListener(data["Receiver"] as string, data["Sender"] as string, from, asyncResult)) { //已有消息,发送消息并结束链接 asyncResult.Complete(null); } return asyncResult; } void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) { //将消息发送到客户端 WebIM_AsyncResult asyncResult = result as WebIM_AsyncResult; asyncResult.Send(m_Context); } void IHttpHandler.ProcessRequest(HttpContext context) { } bool IHttpHandler.IsReusable { get { return true; } }}public class WebIM_AsyncResult : IAsyncResult{ AsyncCallback m_AsyncCallback = null; object m_Data = null; bool m_IsCompleted = false; public WebIM_AsyncResult(AsyncCallback callback, Object extraData) { m_Data = extraData; m_AsyncCallback = callback; } bool IAsyncResult.IsCompleted { get { return m_IsCompleted; } } bool IAsyncResult.CompletedSynchronously { get { return false; } } WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } } Object IAsyncResult.AsyncState { get { return m_Data; } } StringBuilder m_Cache = new StringBuilder(); public void Write(object content) { m_Cache.Append(content.ToString()); } public void Send(HttpContext context) { context.Response.Write(m_Cache.ToString()); } public void Complete(object data) { m_AsyncCallback(this); m_IsCompleted = true; }}
WebIM源代码(注意:开发时起始页为WebIM_Dev.htm,直接打开起始页为WebIM.htm)
一个简单的WebIM就先介绍到这里,如果您有任何问题,可以通过WebIM与我联系。
以下是广告时间,主要介绍云翔在线软件平台的最新动态。此次更新主要修改了平台的操作界面,新的界面将平台所有功能入口放到了网页的上部分,其余版面用于浏览网页,您可以自己设定一个常用的页面作为首页,系统启动后将自动打开您设置的页面。如图所示:
尽管使用了新的界面,原来的桌面模式仍然保留,您可以在登录时切换登录模式:
转载于:https://www.cnblogs.com/sunnylu28/archive/2010/04/24/1719468.html
一步一步打造WebIM(1) (转载)相关推荐
- WPF+WCF一步一步打造音频聊天室(一):概述
前几天在老徐的MSN群中聊WCF.我突然想到了用WPF和WCF来打造音频聊天室这么一个轮子.其实是这样的,我在的公司是两岸三地合作开发的.两岸是指大陆和台湾,三地是指深圳.台北.高雄.由于公司很小,所 ...
- 天龙八步-》打造debian-desktop-》配置桌面[三](转)
天龙八步->打造debian-desktop->配置桌面[三](转)[@more@] 第三章 配置桌面 1.配置simsun字体到:(以下1和2可建立脚本文件/bat/xconf来作) 建 ...
- 天龙八步-》打造debian-desktop-》安装声卡[五](转)
天龙八步->打造debian-desktop->安装声卡[五](转)[@more@] 第五章 安装声卡(alsa方式) 方法一:apt方法 比如我的声卡为ac97的via8233: 1.a ...
- 天龙八步-》打造debian-desktop-》安装桌面和软件[二](转)
天龙八步->打造debian-desktop->安装桌面和软件[二](转)[@more@] 第二章 安装桌面和软件 1.tasksel与dselect: tasksel: 安装三个东西:X ...
- 一步一步学Silverlight 2系列(32):图形图像综合实例—“功夫之王”剧照播放_转载...
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- 一步一步学Silverlight 2系列(22):在Silverlight中如何用JavaScript调用.NET代码_转载...
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- 一步一步学Silverlight 2系列(3):界面布局_转载
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- 一步一步教你玩转.NET Framework的配置文件app.config (转载)
一步一步教你玩转.NET Framework的配置文件app.config 在一般的项目中,为了使你的代码更加灵活,更方便调整,减少不必要的hard code,我们都在config中添加许多配置信息, ...
- 一步一步学Silverlight 2系列(5):实现简单的拖放功能_转载
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- PVE虚拟服务器配置,我与PVE的交往史 篇一:如何使用虚拟机PVE一步一步打造自己想要的ALL IN ONE 主机...
我与PVE的交往史 篇一:如何使用虚拟机PVE一步一步打造自己想要的ALL IN ONE 主机 2021-03-15 00:08:12 79点赞 381收藏 33评论 创作立场声明:我是一个折腾的人, ...
最新文章
- 国内阿里Maven仓库镜像Maven配置文件Maven仓库速度快
- stl的set,multiset, map, multimap, deque, list, stack, queue, priority_queue
- Ubuntu apt-get 源详解
- 原型模式的应用场景_前端常用设计模式
- java应用性能指标_性能与可靠性:Java应用为何像F1汽车
- (STL,set,priority_queue)丑数
- 云计算(1)---基础知识
- 不到2公里要价5400元,货拉拉还能拉多久?
- 综观java读取和创建excel方法
- 计算机生存代码,方舟生存进化OL代码大全 最新最全的代码
- 20155236 《信息安全概论》实验二(Windows系统口令破解)实验报告
- 【使用Redis分布式锁实现优惠券秒杀功能】-Redis学习笔记05
- 超好用的PDF阅读器——Xodo PDF Reader
- 首发 | 杭派工程师五年生存现状报告
- 网易游戏是如何做测试的?
- Python 石墨烯边缘磁性Hatree_Fock计算
- impala查询报错问题 EOFException: Cannot seek after EOF 求解
- Python爬虫之XPath基础教程:用代码抓取网页数据
- pg.Pool 的 query 用法
- JAVA实现斐波那契数列(古典兔子问题)
热门文章
- 数据分析基本思路及手法
- 专门为某种用途而设计的计算机 称为,专门为某种用途而设计的计算机,称为计算机...
- swagger连接mysql数据库_一键生成数据库文档,堪称数据库界的Swagger,有点厉害!...
- Leetcode-496-下一个更大元素 I
- 【备忘】加入L2范数正则化后的正规方程求解参数推导过程
- 2022年考研计算机-数据库原理8-11章
- 连接数mysql证登录名和密码_mysql连接数
- 改变函数this指向
- cesium版本之间如何兼容_【JS】cesium与three.js 结合的栗子,结合了一下网友们的栗子,解决了three.js 高版本模型出不来的问题...
- 文件--非连续空间存放方式