在ESFramework 4.0 快速上手一文中,主要介绍了如何使用ESPlus.Rapid命名空间中的引擎来快速地构建基于TCP的网络通信系统,即使是使用ESPlus.Rapid来进行ESFramework快速开发,也还有很多可以介绍的内容,于是,我想再多写几篇文章来说明现实通信系统中的一些常见需求如何使用ESFramework快速实现。本文是为第一篇,介绍离线消息的原理和实现。

一.如何截获离线消息  

  阅读了ESFramework 4.0 快速上手朋友都知道,一个在线用户给另一个用户发送文本信息或二进制信息采用的是ESPlus.Application.CustomizeInfo.Passive.ICustomizeInfoOutter接口的Send方法,如发送二进制信息:


        /// <summary>
        /// 向在线用户targetUserID发送二进制信息。如果目标用户不在线,则服务端会调用ICustomizeInfoBusinessHandler.OnTransmitFailed方法来通知应用程序。
        /// </summary>
        /// <param name="targetUserID">接收消息的目标用户ID</param>
        /// <param name="informationType">自定义信息类型</param>
        /// <param name="info">二进制信息</param>      
        void Send(string targetUserID, int informationType, byte[] info);       

  对于类似在线用户发给其他用户的P2P类型的消息,可以通过P2P通道发送,也可以通过服务器中转。当目标用户不在线时,P2P通道肯定是不存在的,所以消息一定是提交到服务器。服务器接收到要转发的P2P消息时,判断目标用户是否在线,如果在线,则直接转发;否则,框架会回调ESPlus.Application.CustomizeInfo.Server.ICustomizeInfoBusinessHandler接口的OnTransmitFailed方法:

        /// <summary>
        /// 当因为目标用户不在线而导致服务端转发自定义信息失败时,框架将调用此方法来通知应用程序。
        /// </summary>
        /// <param name="information">转发失败的信息</param>      
        void OnTransmitFailed(Information information);

我们只要实现ICustomizeInfoBusinessHandler接口的这个方法就可以监控到所有的离线消息了。

二.离线消息管理

  截获到离线消息后,我们可能需要将其存到数据库,然后,等到目标用户上线的时候,再从数据库中提取属于该用户的离线消息发送给他即可。

  首先,我们需要对离线消息做一个封装 -- OfflineMessage:


  接下来,我们定义IOfflineMessageManager接口,用于管理离线消息:


    /// <summary>
    /// 离线消息管理器。
    /// </summary>
    public interface IOfflineMessageManager
    {
        /// <summary>
        /// 存储离线消息。
        /// </summary>       
        /// <param name="msg">要存储的离线消息</param>
        void Store(OfflineMessage msg);         /// <summary>
        /// 提取目标用户的所有离线消息。
        /// </summary>       
        /// <param name="destUserID">接收离线消息用户的ID</param>
        /// <returns>属于目标用户的离线消息列表,按时间升序排列</returns>
        List<OfflineMessage> Pickup(string destUserID);
    }

  实现这个接口,我们便可以将离线消息存储到数据库或文本或网络等等,然后等到需要时再次从中提取。

三.存储离线消息

  有了IOfflineMessageManager接口,我们便可以实现ICustomizeInfoBusinessHandler接口的OnTransmitFailed方法了:

        private IOfflineMessageManager offlineMessageManager = ......;
        public void OnTransmitFailed(Information information)
        {
            OfflineMessage msg = new OfflineMessage(information.SourceID, information.DestID, information.InformationType, information.Content);
            this.offlineMessageManager.Store(msg);
        }

  我们也许并不需要将所有的离线消息都存储起来,有些不重要的离线消息可以丢弃,而只保存那些我们关心的消息。这只需要在存储消息之前加一个条件判断进行过滤即可。

四.提取并发送离线消息

  我们已经知道,可以通过IUserManager的SomeOneConnected事件来得知某个用户上线了,于是,我们可以在该事件处理函数中,提取属于该用户的离线消息并发送给他。我们通过类似下面的代码来做到这一点。


    public class OfflineMessageBridge
    {
        #region UserManager
        private IUserManager userManager;
        public IUserManager UserManager
        {
            set { userManager = value; }
        } 
        #endregion         #region OfflineMessageManager
        private IOfflineMessageManager offlineMessageManager;
        public IOfflineMessageManager OfflineMessageManager
        {
            set { offlineMessageManager = value; }
        } 
        #endregion         #region CustomizeInfoController
        private ICustomizeInfoController customizeInfoController;
        public ICustomizeInfoController CustomizeInfoController
        {
            set { customizeInfoController = value; }
        } 
        #endregion         public void Initialize()
        {
            this.userManager.SomeOneConnected += new CbGeneric<ESFramework.Server.UserManagement.UserData>(userManager_SomeOneConnected);
        }                    void userManager_SomeOneConnected(ESFramework.Server.UserManagement.UserData userData)
        {
            List<OfflineMessage> list = this.offlineMessageManager.Pickup(userData.UserID);
            if (list != null && list.Count > 0)
            {
                foreach (OfflineMessage msg in list)
                {
                    this.customizeInfoController.Send(msg.DestUserID, msg.InformationType, msg.Information);
                }
            }
        }
    }

  当用户上线时,会将属于他的离线消息按照时间的顺序一一发送给他。当然,你也可以将属于他的所有离线消息打成一个包,一次性发送也可以。如果是这样,你就需要再增加一条自定义的信息类型和相关的协议类了。

五.小结

  从上面可以看出,基于ESFramework实现离线消息策略是相当简单的,最主要的焦点有两个:第一是可以通过实现ICustomizeInfoBusinessHandler接口来截获到所有的离线消息;第二是通过IUserManager的SomeOneConnected事件就能知道用户上线的时刻。

  有的朋友可能会问离线文件又该怎么实现了?实际上也是同样的原理,只不过要多用到ESPlus.Application.FileTransfering命名空间下的一些类来完成文件的收发功能,这个等有时间的时候再来介绍。

  本文只是实现离线消息的一个简单示例,在实际的应用中,可能需要做更多的工作来满足项目的具体需要,这里就不再一一赘述了。

离线消息如何实现?-- ESFramework 4.0 快速上手(02)的更多相关文章

  1. ESFramework 4.0 快速上手(01) -- Rapid引擎

    (在阅读该文之前,请先阅读 ESFramework 4.0 概述 ,会对本文的理解更有帮助.) ESFramework/ESPlatform 4.0 的终极目标是为百万级的用户同时在线提供支持,因为强 ...

  2. 聊天系统Demo,增加Silverlight客户端(附源码)-- ESFramework 4.0 快速上手(09)

    在ESFramework 4.0 快速上手 -- 入门Demo,一个简单的IM系统(附源码)一文中,我们介绍了使用ESFramework的Rapid引擎开发的winform聊天程序,本文我们将在之前d ...

  3. ESFramework 4.0 快速上手(06) -- Rapid引擎(续)

    <ESFramework 4.0 快速上手>系列介绍的都是如何使用Rapid引擎(快速引擎) -- RapidServerEngine 和 RapidPassiveEngine.其实,大家 ...

  4. 如何使用自定义消息?--ESFramework 4.0 快速上手(04)

    在ESFramework 4.0 快速上手一文中,我们讲述了如何使用Rapid引擎可以快速地上手ESFramework开发,文中介绍了使用ESPlus.Application.CustomizeInf ...

  5. 聊天系统Demo,增加文件传送功能(附源码)-- ESFramework 4.0 快速上手(14)

    本文我们将介绍在ESFramework 4.0 快速上手(08) -- 入门Demo,一个简单的IM系统(附源码)的基础上,增加文件传送的功能.如果不了解如何使用ESFramework提供的文件传送功 ...

  6. 监控自定义信息 —— ESFramework 4.0 快速上手(10)

    在ESFramework 4.0 进阶(02)-- 核心:消息处理的骨架流程一文中,我们介绍了通过挂接IMessageSpy到骨架流程,我们就可以监控到所有收发的消息.由于Rapid引擎已经为我们组装 ...

  7. 重登陆模式 --ESFramework 4.0 快速上手(07)

    在ESFramework框架中基于TCP的服务端引擎(当然也包括Rapid引擎)都采用了这样一条规则:默认情况下,客户端与服务器成功建立TCP连接以后,服务端会从客户端发过来的第一条消息中取出消息头的 ...

  8. 文件传送,如此简单--ESFramework 4.0 快速上手(13)

    在所有的通信系统中,文件传送是最常见也是最重要的功能之一,ESFramework对文件传送的强大支持也是其亮点之一,使用ESFramework可以非常轻松地实现与文件传送相关的所有需求.ESPlus. ...

  9. 使用紧凑的序列化器,数倍提升性能 —— ESFramework 4.0 快速上手(11)

    在分布式通信系统中,网络传递的是二进制流,而内存中是我们基于对象模型构建的各种各样的对象,当我们需要将一个对象通过网络传递给另一个节点时,首先需要将其序列化为字节流,然后通过网络发送给目标节点,目标节 ...

随机推荐

  1. Linux升级glibc

    参考http://www.linuxidc.com/Linux/2015-04/116472.htm via 红孩儿你好 一.简介 glibc是gnu发布的libc库,即c运行库.glibc是linu ...

  2. PHP定义静态方法的原则

    与实例逻辑无关 与类逻辑有关 静态类本质上跟纯函数没区别. 1.static方法是类中的一个成员方法,属于整个类,即使不用创建任何对象也可以直接调用! 2.静态方法效率上要比实例化高,静态方法的缺点是 ...

  3. Front-End(五)——工具使用

    mac端推荐使用sublime+emmet. 环境搭建 sublime 官网下载sublime text 02或者03,03现在(2016.07)还是测试版,我使用的是text02. emmet su ...

  4. pack://application:,,,/

    FrameworkElementFactory gridFactory = new FrameworkElementFactory(typeof(Grid)); gridFactory.SetValu ...

  5. eclipse 配置 Tomcat 遇到的问题以及解决办法

    Eclipse是一个开发JSP的很好的工具,而笔者在配置Tomcat服务器的时候遇到了一些小问题,在这里给大家总结一些经验,希望能帮助同样遇到这些问题的广大同行们能够简单轻松地解决这些问题~ 笔者在以 ...

  6. 连接到sql server 2008 TCP、IP出错

    1.点击 开始 --> 所有程序 --> Microsoft SQL Server2008 --> 配置工具-->SQL Server  configuration Manag ...

  7. linux awk命令详解2

    awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出 awk命令形式: awk [-F ...

  8. Mybatis的传参

    最近重新温习了遍Mybatis ,觉得还是汇总一下比较好,方便自己以后的快速开发 最终要的一点事,自己写的话,记忆更加深刻: 首先自己先写了个静态块,防止代码冗余: private static Sq ...

  9. Spring 配置文件XML -- <beans>中属性概述

    beans : xml文件的根节点. xmlns : XML NameSpace的缩写,因为XML文件的标签名称都是自定义的,自己写的和其他人定义的标签很有可能会重复命名,而功能却不一样,所以需要加上 ...

  10. Mysql索引基础

    Mysql索引基础 基本概念: 索引是一种特殊的数据库结构,可以用来快速查询数据库表中的特定记录.索引是提高数据库性能的重要方式.索引创建在表上,是对数据库表中一列或多列的值进行排序的一种结构.可以提 ...