好友与组--ESFramework 4.0 进阶(11)
大部分分布式通信系统中,都会涉及到客户端之间相互通信、以及需要将客户端进行分组的功能,或者是类似这方面的需求。ESFramework对这一常见的任务内置了强大的支持,包括从客户端到服务端、一直到Platform的群集。在设计时,我们就考虑到了如何对常见的好友通信与组广播通信进行最大的支持,以期让ESFramework的使用者非常容易的就能够使用这些功能。
在ESFramework中,好友与组的成员并不仅仅是指用户(某人),而是指所有运行的客户端实例。只要两个客户端实例之间需要频繁相互通信,那么它们就可以建立好友关系(friend)。如果需要在某些特定的客户端实例间进行广播通信,那么这些实例就可以被划分到同一个组,成为组友(groupmate)。如果是使用ESFramework开发IM系统,那么这两种关系就更明显,它们就类似QQ的好友与群。
一.非强制性依赖
ESFramework提供了好友管理和组管理的接口(IFriendsManager与IGroupManager),如果你的应用需要好友与组方面的功能,那么只要实现这两个接口,并注入到ESFramework框架中,就可以拥有ESFramework内置的好友与组方面的强大功能了。但是,如果你的应用中仅仅是客户端与服务器进行通信,不需要好友与组方面的功能,那么,你就可以直接使用框架内置的null object模式的EmptyFriendsManager和EmptyGroupManager作为占位符对象。
ESFramework 并不会强制性地要求你的应用必须要实现一个与自己的项目需求没有任何关系的接口(比如IFriendsManager与IGroupManager)。我们将选择的权利交到了你的手中,你可以根据项目的具体需求,决定要实现哪些接口,并注入到ESFramework框架中。甚至,你可以只实现IFriendsManager和使用EmptyGroupManager;或者反过来,只实现IGroupManager和使用EmptyFriendsManager。要如何做,完全取决于你的项目要求。
二.好友管理
ESFramework 内置了最简单的好友管理接口ESPlus.Core.Server.IFriendsManager,其定义如下:
public interface IFriendsManager
{
/// <summary>
/// 获取好友列表。
/// </summary>
List<string> GetFriendList(string ownerID);
}
该方法用于获取某个用户的所有好友的UserID列表。同很多常见的返回集合的方法设计规则一样,该方法不允许返回null,如果目标用户没有任何好友,那么请返回元素个数为0的List。接下来我们看,有了IFriendsManager这个接口,框架可以提供哪些与好友相关的功能或特性。
(1)用户上/下线时,通知其好友。当用户上线或下线时,框架会回调ESPlus.Application.Basic.Passive.IBasicBusinessHandler接口的OnFriendConnected方法或OnFriendOffline方法以通知所有的在线好友。
(2)客户端可以通过ESPlus.Application.Basic.Passive.IBasicOutter接口的GetFriends方法和GetAllOnlineFriends方法来获取所有好友以及所有在线的好友列表。
有了这两组特性的支持,每个运行的客户端实例,在其运行的整个生命周期中,都可以清楚地知道每个好友的在线状态。在具体项目中,我们可以这么做,当某个客户端登陆成功后,就获取所有好友列表和所有的在线好友列表,然后在运行的过程中,当接收到IBasicBusinessHandler的回调通知时,就修改对应好友的状态。这样就保证我们的客户端可以实时地知道每个好友是否在线。
ESFramework 内置了IFriendsManager接口的两个实现,一个就是上面提到的占位符EmptyFriendsManager,还有一个是DefaultFriendsManager。
(1)EmptyFriendsManager 假设所有的用户都不是好友关系 -- 即其GetFriendList方法始终返回一个元素个数为0的列表。
(2)DefaultFriendsManager 则假设所有的在线用户都是好友 -- 即其GetFriendList方法始终返回所有在线用户列表(将自己ownerID排除在外)。
三.组管理
组管理比好友管理稍微复杂一些,其复杂是因为一个用户可以加入到多个组,而且不同的组的成员是可以重复的。ESFramework 内置了最简单的组管理接口ESPlus.Core.Server.IGroupManager,其定义如下:
public interface IGroupManager
{
/// <summary>
/// 获取某个组的所有成员列表。
/// </summary>
/// <param name="groupID">目标组ID</param>
/// <returns>组成员的UserID列表</returns>
List<string> GetMemberList(string groupID); /// <summary>
/// 获取目标用户的组友列表(即目标用户所属的所有组的成员的并集)。
/// </summary>
/// <param name="userID">目标用户ID</param>
/// <returns>组友的UserID的列表。注意,该列表不应包含目标用户自己。</returns>
List<string> GetGroupmateList(string userID); /// <summary>
/// 获取目标用户加入的所有组的ID集合。
/// </summary>
/// <param name="userID">目标用户的UserID</param>
/// <returns>包含了userID用户的所有组的ID列表</returns>
List<string> GetOwnerGroupIDList(string userID);
}
(1)这三个方法都返回一个列表,所以也遵循相同的方法设计规则:如果没有任何满足条件的结果,请返回元素个数为0的List。
(2)GetMemberList 用于获取一个组的所有成员列表。比如,在实现该接口时,我们可以从DB中加载目标组及组成员,然后返回成员列表。
(3)组友groupmate,即同属一个组的成员之间的相互关系。由于一个用户可以加入到多个组,所有其组友就是所有这些组的成员的并集。注意,GetGroupmateList方法返回的列表中不能包含重复的UserID。
(4)一个用户可以属于多个组,GetOwnerGroupIDList方法用于获取某个用户加入的所有组的GroupID的列表。
接下来我们看,有了IGroupManager这个接口,框架可以提供哪些与组相关的功能或特性。
(1)用户上/下线时,通知其所有组友。当用户上线或下线时,框架会回调ESPlus.Application.Basic.Passive.IBasicBusinessHandler 接口的OnGroupmateConnected方法或OnGroupmateOffline方法以通知所有的在线组友。
(2)客户端可以通过ESPlus.Application.Basic.Passive.IBasicOutter接口的GetAllOnlineGroupmates方法来获取所有在线的组友列表。
(3)当我们发送组广播消息时(比如ESPlus.Application.CustomizeInfo.Passive.ICustomizeInfoOutter 接口的BroadcastInGroup方法),框架通过IGroupManager接口的GetMemberList方法才知道要将消息广播给哪些用户。
同IFriendsManager一样,有了(1)和(2)特性的支持,每个运行的客户端实例,在其运行的整个生命周期中,就可以清楚地知道每个组友的在线状态了。
ESFramework 内置了IGroupManager接口的一个实现,就是前面提到的占位符EmptyGroupManager,它对接口的三个方法的实现都是返回元素个数为0的列表。
四.与ESPlatform的集成
ESPlatform的主要目的是通过应用服务器的群集以支持巨大并发。当将一个基于ESFramework的通信系统迁移到ESPlatform时,与好友和组相关的功能特性仍然可以正常使用。服务端和客户端程序几乎不需要修改,只需要将服务端原先配置的本地的IFriendsManager引用和IGroupManager引用修改为ESPlatform中平台层的对应的全局的Remoting引用即可,可以参见ESFramework 4.0 进阶(09)-- ESPlatform 支持的三种群集模型 一文简单了解平台层以及全局的FriendServer和GroupSever。
五.请注意性能
如果具体的项目中需要频繁地用到好友与组等特性,那么在实现IFriendsManager接口和IGroupManager接口时,要特别注意性能问题。因为IFriendsManager接口和IGroupManager接口的方法会被框架频繁调用,所以,必须想办法提高IFriendsManager和IGroupManager接口的实现的性能。
如果IFriendsManager和IGroupManager接口的方法被调用时,每次都需要从外部介质(比如DB、文件等)重新加载好友关系与组关系,那么毫无疑问将严重地降低应用程序的性能。通常的解决方案是,使用缓存避免重复读取。当好友关系与组关系没有发生变化时,直接从内存返回对应的列表。
至于究竟采用何种策略来提升IFriendsManager和IGroupManager的性能,需要根据你的项目具体情况而作妥当设计。特别是在高性能的分布式通信系统中,这一点是万万不可忽视的。
好友与组--ESFramework 4.0 进阶(11)的更多相关文章
- 垂直分割群集模型与多通道引擎 -- ESFramework 4.0 进阶(10)
在ESFramework 4.0 进阶(09)-- ESPlatform 支持的三种群集模型一文中,我们介绍了ESPlatform支持的三种群集模型 -- 垂直分割模型.水平分割模型.交叉模型.我们看 ...
- 消息同步调用-- ESFramework 4.0 进阶(07)
分布式系统的构建一般有两种模式,一是基于消息(如Tcp,http等),一是基于方法调用(如RPC.WebService.Remoting).深入想一想,它们其实是一回事.如果你了解过.NET的Prox ...
- 挂接P2P通道-- ESFramework 4.0 进阶(08)
最新版本的ESFramework/ESPlus提供了基于TCP和UDP的P2P通道,而无论我们是使用基于TCP的P2P通道,还是使用基于UDP的P2P通道,ESPlus保证所有的P2P通信都是可靠的. ...
- 在线用户管理--ESFramework 4.0 进阶(05)
无论我们采用何种通信框架来构建我们的分布式系统,在服务端进行用户管理都是非常重要的一个环节.然而用户管理是否应该隶属于通信框架了?这个并不一定,通常来说,用户管理是与具体应用紧密相关的,应该是由应用解 ...
- 正规消息发送器-- ESFramework 4.0 进阶(06)
在ESFramework 4.0 进阶(04)-- 驱动力:通信引擎(下)一文末尾我们已经将通信引擎以及整个消息骨架流程组装起来了,只要通信引擎一接收到消息,框架就会按照规定的流程进行运转.到这里,自 ...
- ESFramework 4.0 进阶(04)-- 驱动力:通信引擎(下)
在ESFramework 4.0 进阶(03)-- 驱动力:通信引擎(上)一文中,我们对ESFramework提供的每一个通信引擎的接口都做了详细了说明,这篇文章我们将继续探讨这些接口的实现类 -- ...
- 驱动力—— 通信引擎(上)—— ESFramework 4.0 进阶(03)
在ESFramework 4.0 进阶(02)-- 核心:消息处理的骨架流程一文中我们详细介绍了ESFramework中消息处理的骨架流程,并且我们已经知道,ESFramework中的所有通信引擎使用 ...
- 核心梳理——消息处理的骨架流程——ESFramework 4.0 进阶(02)
在ESFramework 4.0 概述一文中,我们提到ESFramework.dll作为通信框架的核心,定义了消息处理的骨架流程,本文我们来详细剖析这个流程以及该骨架中所涉及的各个组件.ESFrame ...
- ESFramework 4.0 进阶(01)-- 消息
需要交互的分布式系统之间通过消息来传递有意义的信息.消息是通信框架的核心.离开了消息,再谈通信框架就没有任何意义,所以,消息是ESFramework中一个最核心的概念. 一. 消息的类别 在具体的应用 ...
随机推荐
- 一步步优化JVM六:优化吞吐量
如果你已经进行完了前面的步骤了,那么你应该知道这是最后一步了.在这一步里面,你需要测试应用的吞吐量和为了更高的吞吐量而优化JVM. 这一步的输入就是应用的吞吐量性能要求.应用的吞吐量是在应用层面 ...
- [转]学好Mac常用命令,助力iOS开发
转自:http://www.jianshu.com/p/d9ec00d28237 序言 在iOS开发的过程中,更多地注重iOS开发的效率,熟练使用Mac终端操作的常用命令,可以让你更好的游刃于iO ...
- HDU 5904 LCIS
$dp$. 这题的突破口在于要求数字是连续的. 可以分别记录两个串以某个数字为结尾的最长上升长度,然后枚举一下以哪个数字为结尾就可以得到答案了. 因为$case$有点多,不能每次$memset$,额外 ...
- 个性化推荐系统中的BadCase分析
针对内测用户反馈,由于前一天点击了几个动画,导致第二天推荐的动画屏占比较高,于是开始对此badcase进行分析. 首先分析了该用户的历史观看纪录,由于系统升级,日志缺陷问题,导致该用户10.15-11 ...
- 在ubuntu下设置eclipse开发STM32等嵌入式设备
之前为了能够让ROS与底层能够顺利通讯,我采用可开源开发板arduino ,因为arduino有ROS的库,能够按照ROS wiki上所给的教程就可以顺利的开发,但由于arduino的局限性,我觉得是 ...
- [DP优化方法之斜率DP]
什么是斜率dp呢 大概就把一些单调的分组问题 从O(N^2)降到O(N) 具体的话我就不多说了 看论文: http://www.cnblogs.com/ka200812/archive/2012/08 ...
- 如何在无法直接用VS启动代码时如何调试代码
1. 普通情况下对进程Attach就可以调试. 2. 但是在一些情况下直接attach并无法调试,例如安装程序installer, 这样使用如下的调试方法即可调试安装程序. System.Diagno ...
- Java集合初体验
背景: 因为对Java的集合完全不了解,所以才在网上找了找能形成初步印象的文章进行学习,大多涉及的是一些概念和基础知识. 一.数组array和集合的区别: (1)数组是大小固定的,并且同 ...
- c#代码发送post请求,上传文件(并带其他参数)
本人对post理解不深,前段时间遇到一个需要用c#代码发送post请求上传文件的业务,于是参考了几篇帖子,加上自身实践写出了如下代码.写的比较low 望各位大大指正^_^. 业务需求: 对方给了一个接 ...
- Linux 网络性能tuning向导
本文的目的不完全在于提供调优信息,而是在于告诉读者了解Linux kernel如何处理数据包,从而能够在 自己的实践中发挥Linux 内核协议栈最大的性能 The NIC ring buffer 接收 ...