ESFramework 4.0 快速上手(02) -- 离线消息如何实现?

  在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

View Code
    [ Serializable]
    
public   class   OfflineMessage
    {
        
#region  Ctor
        
public  OfflineMessage() { }
        
public  OfflineMessage( string  _sourceUserID,  string  _destUserID,  int  _informationType,  byte[]  info)
        {
            
this .sourceUserID  =  _sourceUserID;
            
this .destUserID  =  _destUserID;
            
this .informationType  =  _informationType;
            
this .information  =  info;
        } 
        
#endregion

        
#region  SourceUserID
        
private   string  sourceUserID  =   "" ;
        
///   <summary>
        
///  发送离线消息的用户ID。
        
///   </summary>
         public   string  SourceUserID
        {
            
get  {  return  sourceUserID; }
            
set  { sourceUserID  =  value; }
        } 
        
#endregion

        
#region  DestUserID
        
private   string  destUserID  =   "" ;
        
///   <summary>
        
///  接收离线消息的用户ID。
        
///   </summary>
         public   string  DestUserID
        {
            
get  {  return  destUserID; }
            
set  { destUserID  =  value; }
        } 
        
#endregion

        
#region  InformationType
        
private   int  informationType  =   0 ;
        
///   <summary>
        
///  信息的类型。
        
///   </summary>
         public   int  InformationType
        {
            
get  {  return  informationType; }
            
set  { informationType  =  value; }
        } 
        
#endregion

        
#region  Information
        
private   byte[]  information;
        
///   <summary>
        
///  信息内容
        
///   </summary>
         public   byte[]  Information
        {
            
get  {  return  information; }
            
set  { information  =  value; }
        } 
        
#endregion       
   
        
#region  Time
        
private  DateTime time  =  DateTime.Now;
        
///   <summary>
        
///  服务器接收到要转发离线消息的时间。
        
///   </summary>
         public  DateTime Time
        {
            
get  {  return  time; }
            
set  { time  =  value; }
        } 
        
#endregion
    }

  接下来,我们定义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 概述 (文末包含最新版本的ESFramework4.0以及相关demo、帮助文档下载)

《ESFramework 4.0 快速上手》系列所有文章

《ESFramework 4.0 高级进阶》系列所有文章

 

你可能感兴趣的:(framework)