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
 1 public class TcpUserManagerBridge
 2     {
 3         private IBasicRequestDealer basicRequestDealer = null ;
 4         private ITcpUserManager     tcpUserManager     = null ;
 5         private ITcp                theTcp               = null ;
 6         private IContractHelper     contractHelper     = null ;
 7         private bool                directSeviceCommitEnabled = false ;
 8         
 9 
10         public TcpUserManagerBridge()
11         {
12             
13         }
14 
15         public void Initialize()
16         {
17             this.theTcp.ServiceCommitted                         += new CallBackRespond(theTcp_ServiceCommitted);
18             this.theTcp.SomeOneDisConnected                         += new CallBackDisconnect(theTcp_SomeOneDisConnected);
19             this.basicRequestDealer.RequestWithoutRespondArrived += new CbSimpleStr(basicRequestDealer_RequestWithoutRespondArrived);
20             this.basicRequestDealer.SomeOneLogout                += new CbSimpleStr(basicRequestDealer_SomeOneLogout);
21             this.theTcp.ServiceDirectCommitted                   += new CallBackRespond(theTcp_ServiceDirectCommitted);
22         }
23 
24         #region property
25         public ITcpUserManager TcpUserManager
26         {
27             set
28             {
29                 this.tcpUserManager = value ;
30             }
31         }
32 
33         public ITcp Tcp
34         {
35             set
36             {
37                 this.theTcp = value ;
38             }
39         }
40 
41         public IBasicRequestDealer BasicRequestDealer
42         {
43             set
44             {
45                 this.basicRequestDealer = value ;
46             }
47         }
48 
49         public IContractHelper ContractHelper
50         {
51             set
52             {
53                 this.contractHelper = value ;
54             }
55         }
56 
57         public bool DirectSeviceCommitEnabled
58         {
59             set
60             {
61                 this.directSeviceCommitEnabled = value ;
62             }
63         }
64         #endregion        
65 
66         private void theTcp_SomeOneDisConnected(int ConnectID, DisconnectedCause cause)
67         {
68             this.tcpUserManager.DisposeOneConnection(ConnectID ,cause) ;
69         }
70 
71         private void basicRequestDealer_RequestWithoutRespondArrived(string userID)
72         {
73             this.tcpUserManager.ActivateUser(userID) ;
74         }
75 
76         private void basicRequestDealer_SomeOneLogout(string userID)
77         {
78             this.tcpUserManager.DisposeOneUser(userID ,DisconnectedCause.Logoff) ;
79         }        
80 
81         private void theTcp_ServiceCommitted(int connectID, NetMessage msg)
82         {
83             this.tcpUserManager.ServiceCommited(connectID ,msg.Header.UserID ,msg.Header.ServiceKey ,msg.Header.MessageBodyLength + this.contractHelper.MessageHeaderLength) ;
84         }
85 
86         private void theTcp_ServiceDirectCommitted(int connectID, NetMessage msg)
87         {
88             if(this.directSeviceCommitEnabled)
89             {            
90                 this.tcpUserManager.ServiceCommited(connectID ,msg.Header.UserID ,msg.Header.ServiceKey ,msg.Header.MessageBodyLength + this.contractHelper.MessageHeaderLength) ;
91             }
92         
93         }
94     }

    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 可复用的通信框架(序) 

 
   

 

时间: 2024-07-30 01:54:34

ESFramework介绍之(18)―― Tcp用户管理器组件的相关文章

推荐一个简单、轻量、功能非常强大的C#/ASP.NET定时任务执行管理器组件–FluentScheduler

原文:推荐一个简单.轻量.功能非常强大的C#/ASP.NET定时任务执行管理器组件–FluentScheduler 在C#WINFORM或者是ASP.NET的WEB应用程序中,根据各种定时任务的需求,比如:每天的数据统计,每小时刷新系统缓存等等,这个时候我们得应用到定时器这个东东. .NET Framework有自带的timer,但这个类只能完成一些简单的定时操作,比如间隔多久执行什么操作.遇到一些复杂的定时任务,如从当前时间开始,多少时间后间隔重复执行,timer类处理起来就相对困难了.经过多

.NET可复用TCP通信层之消息分派器组件

上一篇主要讲到了Tcp通信层中的核心组件――Tcp组件的实现,Tcp组件是整个通信层的消息驱动源,甚至,可以将Tcp组件看作是我们整个服务器系统的消息驱动源,消息处理过程从这里引发.类似的消息驱动源还有发布的WebService接口.Remoting接口等.今天我们需要关注的是Tcp通信层中的"中央"组件――消息分派器组件ITcpReqStreamDispatcher,大家已经从前文的组件关系图中看到了消息分派器的大致位置和作用了,它是Tcp通信组件和消息处理器之间的"桥梁&

Windows8凭据管理器查看网页账号密码的秘诀

  日常生活中,经常需要很多的密码来保护个人的隐私,由于很多账号我们很少登录就会常常忘记密码,甚至无法找回,给很多用户造成很大的困扰.下面小编简单介绍一下Win8系统凭据管理器如何找回网页中保存过的账号密码. 一.在电脑桌面,直接按F3打开搜索,在"所有位置"搜索"凭据管理器",然后打开,如下图所示. 二.单击"web凭据",可以看到各个保存过密码的网址以及账号,如下图所示. 三.单击想要删除保存密码的网址,会弹出输入密码的对话框. 四.然后便可

Win8系统凭据管理器找回网页中保存过的账号密码

  日常生活中,经常需要很多的密码来保护个人的隐私,由于很多账号我们很少登录就会常常忘记密码,甚至无法找回,给很多用户造成很大的困扰.下面小编简单介绍一下Win8系统凭据管理器如何找回网页中保存过的账号密码. 一.在电脑桌面,直接按F3打开搜索,在"所有位置"搜索"凭据管理器",然后打开,如下图所示. 二.单击"web凭据",可以看到各个保存过密码的网址以及账号,如下图所示. 三.单击想要删除保存密码的网址,会弹出输入密码的对话框. 四.然后便可

Win7系统通知区域音频管理器图标怎么关闭

  音频管理器主要可以设置音频设备.音量控制.录音机和麦克风等管理,如果开启"Realtek音频管理器"的话,一般也会在windows系统任务栏通知区域中显示音频管理器图标,虽然有助于我们设置,但该程序图标也是很少用得到的,反而会在通知区域占用一席之地,所以有些用户会去选择关闭音频管理器程序图标.下面给大家介绍两种关闭音频管理器技巧. 方法一.关闭音频管理器图标 1.win7 64位旗舰版下载后,随着声卡驱动的更新,Realtek音频管理器会被安装在系统里面.一般来说,默认情况下都是开

Win8系统凭据管理器使用技巧

  Win8系统凭据管理器可以记录各种密码,并以加密的形式将非本地凭据同步到微软账户,就算更换电脑,只需登录相同的微软账户即可,我们只需记住微软账户,其他就交由凭据管理器吧.下面小编就为大家介绍一下Win8系统凭据管理器使用技巧. 在Win8系统中,打开超级按钮-设置-更改电脑设置-OneDrive-同步设置-其他设置,开启密码的同步,即可在微软账号中"携带"您的密码.

《实施Cisco统一通信管理器(CIPT1)》一第2章 部署模型

第2章 部署模型 实施Cisco统一通信管理器(CIPT1)读者应该对Cisco UC(统一通信)的推荐设计方案和部署方案,以及冗余选项进行充分的了解.因为这些方案可以提供与传统语音网络相同,甚至更加优秀的可用性. 这一章我们要介绍CUCM(Cisco统一通信管理器)的部署模型,这些模型可以实现不同程度的冗余.本章介绍的各类冗余模型可以应用于不同的部署模型中,这些模型可以在网络和设备出现故障时使网络具备容错能力.

《实施Cisco统一通信管理器(CIPT1)》——第2章 部署模型

第2章 部署模型 实施Cisco统一通信管理器(CIPT1)读者应该对Cisco UC(统一通信)的推荐设计方案和部署方案,以及冗余选项进行充分的了解.因为这些方案可以提供与传统语音网络相同,甚至更加优秀的可用性. 这一章我们要介绍CUCM(Cisco统一通信管理器)的部署模型,这些模型可以实现不同程度的冗余.本章介绍的各类冗余模型可以应用于不同的部署模型中,这些模型可以在网络和设备出现故障时使网络具备容错能力.

ESFramework介绍之(11)-- Tcp连接池管理器

    上文已经讲到,Tcp连接池管理器为我们的应用进行了很多复杂的管理,比如功能服务器的调度(实现FS的负载均衡).连接池的动态添加/移除.控制每个连接池的相关参数在UI上的显示等,并且连接池管理器与单个连接池拥有一样的接口ITcpPool.我们先回顾一下这个接口:   1     public interface ITcpPool 2     { 3         RentStreamResult RentTcpStream(int poolTypeKey ,int serviceKey