好友与组--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中一个最核心的概念. 一. 消息的类别 在具体的应用 ...
随机推荐
- 常用的 css 样式 记录
1.font-style 属性指定文本的字体样式. 对应的值有: normal 默认值.浏览器显示一个标准的字体样式; italic 浏览器会显示一个斜体的字体样式; oblique 浏览器会显 ...
- HTML学习总结(四)【canvas绘图、WebGL、SVG】
一.Canvas canvas是HTML5中新增一个HTML5标签与操作canvas的javascript API,它可以实现在网页中完成动态的2D与3D图像技术.<canvas> 标记和 ...
- JSONP 的工作原理是什么?
利用<script>标签没有跨域限制的"漏洞"来达到与第三方通讯的目的. 当需要通讯时,本站脚本创建一个<script>元素,地址指向第三方的API网址,形 ...
- 新发现的一些C函数
今天看lsocket代码,发现有三个C函数,以前一直没有用过. 觉得特别有意思,一个strspn,一个strrchr,一个getaddrinfo. strspn #include <string ...
- Html5NodeJs安装less之千辛万苦CMD系列
如题,这个东西很是费了一般脑筋 上一次讲了如何在浏览器端解析less文件,这次是在cmd中使用npm中的less模块来解析 详解如下 首下我们去下载一个NodeJs, 我下载的是4.44版本,一路 ...
- 【 Note 】GDB调试
GDB是在linux下的调试功能 命令: 启动文件: 普通调试 gdb 可执行文件 分屏调试 gdb -tui 可执行文件 ->调试: 运行 r 设置断点 b 删除断点 delete 断点编号 ...
- 百度移动搜索自动转码太坑爹,JS跳转地址会被抓取
这段时间碰到个很崩溃的问题,一个页面通过 script 加载请求服务端进行统计再输出js进行跳转,分为两个步骤分别统计, 打开页面通过script 请求远程服务器进行统计并输出要通过js使页面跳转的最 ...
- Android抽屉效果 DrawerLayout 入门经验总结
今天试了试这个抽屉布局的效果,结果很崩溃无语 网上很多资料都千篇一律,感觉都有问题,下面总结下几点经验: 先上个效果图: 1. layout 布局文件中怎么写: <android.suppor ...
- Hadoop集群出现no data node to stop的解决方案
问题描述: 今天stop hadoop集群的时候出现no datanode to stop ,寻找解决方案,并不是网上资料所说的什么DFS Used .Non DFS Used等于0 .所有的节点都是 ...
- delphi const
参考:http://www.cnblogs.com/tibetwolf/articles/1785744.html 1.const修饰可能会优化编译代码.关于这一点与编译器密切相关,由于变量被cons ...