zoukankan      html  css  js  c++  java
  • ESFramework介绍之(18)―― Tcp用户管理器组件

        当我们的应用中客户端与AS之间是通过Tcp进行通信的时候,通常,应用也要求管理所有在线的用户。这种管理至少包含以下几点:
    (1) 当用户上线时,记录上线时间
    (2) 当用户请求服务时,记录请求服务的时间、服务的类型、本次服务下载的数据量
    (3) 当用户下线时,记录下线时间。并把本次用户登录、请求服务过程中的所有信息持久化保存(如记录到数据库)

        在ESFramework中,实现这种管理的是ITcpUserManager组件,通常,该组件由AS使用(因为在AS、FS、IRAS中只有AS是必须要求提供用户管理功能的)。除了上述功能外,ITcpUserManager组件还提供:
    (1) 控制UI上用户实时状态的显示
    (2) 对用户意外掉线进行定时检查
    (3) 提供用户是否在线的查询
    (4) 提供通过用户ID获取Tcp连接的查询

        为什么ITcpUserManager组件需要提供这些功能?为什么有些功能不在其他组件中提供、而非在ITcpUserManager组件之中不可?这些问题都需要你进行深入的思考,就像我们当初所做的那样。ITcpUserManager组件一开始并不是这样的设计,在经过几次重构改善后才是这个样子,现在这个设计已经稳定下来了。在思考的过程中,你需要记住一点:ITcpUserManager组件是用户状态最全面、最实时发布的地方。
        ITcpUserManager接口定义如下:

     1     public interface ITcpUserManager
     2     {            
     3         void Start() ;
     4         void Stop() ;
     5         
     6         void DisposeOneUser(string userID ,DisconnectedCause cause) ;
     7         void DisposeOneConnection(int connectID  ,DisconnectedCause cause) ;
     8         void ServiceCommited(int connectID ,string userID ,int serviceKey ,int dataCount) ;
     9         void ActivateUser(string userID) ;
    10 
    11         bool  IsUserOnLine(string userID) ;
    12         int   GetUserConnectID(string userID) ;//如果不在线,返回-1
    13         string[] GetOnlineUserList() ;//IList中是在线的userID
    14         
    15         event CbForTcpUserDisconn SomeOneDisconnected ;
    16         event CbSimpleStr         SomeOneConnected ;//UserID
    17         event CbSimple            Restarted ;
    18 
    19         ITcpUserDisplayer TcpUserDisplayer{set ;} //控制UI
    20         IUserTaskReporter UserTaskReporter{set ;} //持久化服务记录清单
    21         int OnLineCheckSpan{get ;set ;}//OnLineCheckSpan单位为分钟,如果不使用定时检查,则onLineCheckSpan为-1
    22 
    23     }

        那么,ITcpUserManager组件从哪里获取用户的这些实时信息了?
    (1) 网络插件的ServiceCommited事件、网络插件的SomeOneDisConnected事件
    (2) 定时检查器的掉线事件
    (3) 基本请求处理者的RequestWithoutRespondArrived事件=》激活定时检查器中的某个用户
    (4) Logout请求
        上述的几个信息来源决定了ITcpUserManager组件与其他几个组件的依赖关系。综合上面所有的,下面是ITcpUserManager组件与其他主要组件的依赖关系图:

        这些依赖关系的组装是由TcpUserManagerBridge类完成的,看看它的代码就知道怎么回事了:

    TcpUserManagerBridge

        TcpUserManagerBridge相当与一种桥接模式(可从这里了解更多),使得组件与组件之间的耦合关系达到最小。

        在ESFramework内部,很多地方需要使用到ITcpUserManager组件,比如P2PMessageDealer组件中、ToLocalClientSender组件中等等,它们主要通过ITcpUserManager组件获取某用户的Tcp连接、或查看某用户是否在线。

        最后提一下ITcpUserManager用到的两个组件:IUserOnLineChecker和IUserTaskReporter。
        IUserOnLineChecker用于实现前面文章中谈到的“定时check消息”机制,当某个用户在指定的时间内没有任何消息发给服务器时,IUserOnLineChecker触发SomeConnectionTimeOuted事件通知该用户已经掉线。IUserOnLineChecker接口定义非常简单:

     1     public interface IUserOnLineChecker
     2     {        
     3         void Start() ;
     4         void Stop() ;
     5 
     6         void RegisterOrActivateUser(string userID) ;        
     7         void UnregisterUser(string userID) ; //被外界调用UnregisterUser时,不触发CheckSomeOneDisConnected事件
     8 
     9         int CheckSpan{get ;set ;} //Minutes
    10 
    11         event CbSimpleStr  SomeConnectionTimeOuted ; //仅是当定时检查出用户掉线时才触发
    12     }    

        前面我们提到,当用户下线(掉线)时,需要把该用户本次登录的服务记录永久存储,这个功能是由IUserTaskReporter来完成的。

     1     public interface IUserTaskReporter
     2     {
     3         void RecordTaskList(ITaskMainRecord mainRecord) ;
     4         ITaskMainRecord    CreateRudeTaskMainRecord() ;
     5         ITaskDetailRecord  CreateRudeTaskDetailRecord() ;
     6     }            
     7 
     8     public interface ITaskMainRecord
     9     {        
    10         string     UserID{get ;set ;}
    11         int         TotalDataCount{get ;set ;}
    12         DateTime TimeLogon{get ;set ;}
    13         DateTime TimeLogout{get ;set ;}        
    14         int         RequestCount{get ;set ;}
    15 
    16         ArrayList Details{get ;set ;}//details中为ITaskDetailRecord
    17     }
    18 
    19     public interface ITaskDetailRecord
    20     {
    21         int      ServiceKey{get ;set ;}
    22         int         DataCount{get ;set ;}
    23         DateTime RequestTime{get ;set ;}        
    24     }

        持久化的具体介质由你的应用决定。如果你使用数据库来存储,则可以将ITaskMainRecord和ITaskDetailRecord在数据库中设计成主从表关系。

        
    上一篇文章:ESFramework介绍之(17)―― 支持漫游用户和跨区域功能请求

    转到  :ESFramework 可复用的通信框架(序) 

     
       

     

  • 相关阅读:
    敏捷软件开发:原则、模式与实践——第4章 测试
    敏捷软件开发:原则、模式与实践——第3章 计划
    敏捷软件开发:原则、模式与实践——第2章 极限编程概述
    敏捷软件开发:原则、模式与实践——第1章 敏捷实践
    编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试
    编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本
    编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码
    编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣
    编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释
    编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释
  • 原文地址:https://www.cnblogs.com/zhuweisky/p/363601.html
Copyright © 2011-2022 走看看