大部分分布式通信系统中,都会涉及到客户端之间相互通信、以及需要将客户端进行分组的功能,或者是类似这方面的需求。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)的更多相关文章

  1. 垂直分割群集模型与多通道引擎 -- ESFramework 4.0 进阶(10)

    在ESFramework 4.0 进阶(09)-- ESPlatform 支持的三种群集模型一文中,我们介绍了ESPlatform支持的三种群集模型 -- 垂直分割模型.水平分割模型.交叉模型.我们看 ...

  2. 消息同步调用-- ESFramework 4.0 进阶(07)

    分布式系统的构建一般有两种模式,一是基于消息(如Tcp,http等),一是基于方法调用(如RPC.WebService.Remoting).深入想一想,它们其实是一回事.如果你了解过.NET的Prox ...

  3. 挂接P2P通道-- ESFramework 4.0 进阶(08)

    最新版本的ESFramework/ESPlus提供了基于TCP和UDP的P2P通道,而无论我们是使用基于TCP的P2P通道,还是使用基于UDP的P2P通道,ESPlus保证所有的P2P通信都是可靠的. ...

  4. 在线用户管理--ESFramework 4.0 进阶(05)

    无论我们采用何种通信框架来构建我们的分布式系统,在服务端进行用户管理都是非常重要的一个环节.然而用户管理是否应该隶属于通信框架了?这个并不一定,通常来说,用户管理是与具体应用紧密相关的,应该是由应用解 ...

  5. 正规消息发送器-- ESFramework 4.0 进阶(06)

    在ESFramework 4.0 进阶(04)-- 驱动力:通信引擎(下)一文末尾我们已经将通信引擎以及整个消息骨架流程组装起来了,只要通信引擎一接收到消息,框架就会按照规定的流程进行运转.到这里,自 ...

  6. ESFramework 4.0 进阶(04)-- 驱动力:通信引擎(下)

    在ESFramework 4.0 进阶(03)-- 驱动力:通信引擎(上)一文中,我们对ESFramework提供的每一个通信引擎的接口都做了详细了说明,这篇文章我们将继续探讨这些接口的实现类 -- ...

  7. 驱动力—— 通信引擎(上)—— ESFramework 4.0 进阶(03)

    在ESFramework 4.0 进阶(02)-- 核心:消息处理的骨架流程一文中我们详细介绍了ESFramework中消息处理的骨架流程,并且我们已经知道,ESFramework中的所有通信引擎使用 ...

  8. 核心梳理——消息处理的骨架流程——ESFramework 4.0 进阶(02)

    在ESFramework 4.0 概述一文中,我们提到ESFramework.dll作为通信框架的核心,定义了消息处理的骨架流程,本文我们来详细剖析这个流程以及该骨架中所涉及的各个组件.ESFrame ...

  9. ESFramework 4.0 进阶(01)-- 消息

    需要交互的分布式系统之间通过消息来传递有意义的信息.消息是通信框架的核心.离开了消息,再谈通信框架就没有任何意义,所以,消息是ESFramework中一个最核心的概念. 一. 消息的类别 在具体的应用 ...

随机推荐

  1. js学习笔记1

    就是调用对象是一个Array,对Array类型增加了一个原型写法的函数,一般写一些扩展时经常用.比如判断一个元素是否在数组中之类的 Array.prototype.inArray=function(v ...

  2. eclipse 中的maven操作

    首先,maven中常用的几个命令: clean  清空target目录 compile  编译 package  打包到target目录 install  打包到本地仓库 -------------- ...

  3. ECS活动真实IP (前端存在SLB)

    log_format main 'realip:$http_x_forwarded_for slbip:$remote_addr-$remote_user [$time_local] "$r ...

  4. hibernate子查询

    对于支持子查询的数据库,Hibernate支持在查询中使用子查询.一个子查询必须被圆括号包围起来(经常是SQL聚集函数的圆括号). 甚至相互关联的子查询(引用到外部查询中的别名的子查询)也是允许的. ...

  5. Mysq 5.7l服务无法启动,没有报告任何错误

    昨天系统崩溃了,然后重装了Mysql 5.7 安装步骤和遇到问题及解决方案. 去官网下载Mysql 5.7的解压包(zip),解压到你要安装的目录. 我的安装目录是:D:\Java\Mysql 安装步 ...

  6. 关于数据汇总方面返回Json数据的小小心得

    在一开始的开发中,计算好相关数据,然后通过 1.拼串 2.实例化Dictory对象再通过JavaScriptSerializer转换为json. 其中,2只适合于二维数据.1适合多维数据,但拼串比较费 ...

  7. linux挂载新硬盘

    Linux添加新硬盘自动挂载硬盘的具体步骤 1.插入新硬盘,启动Linux服务器,使用fdisk -l 查看硬盘 #fdisk -l Disk /dev/sdb: 1000.2 GB, 1000204 ...

  8. Gentoo网络管理方法总结

    OpenRC/netifrc Netifrc is a collection of modules created to configure and manage network interfaces ...

  9. Docker 总结

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+] Docker总结 简单介绍 1 Docker 架构 安装和环境配置 1 mac 11 brew安装 11 dmg文件安装 1 ...

  10. postgreSQL-如何查数据库表、字段以及字段类型、注释等信息?

    之前从网上也搜索了一些关于postgreSQL的系统表含义以及如何查表相关信息,但是都没有一个完整的内容,所以自己将找到的一些内容作了下整合,大家可以根据自己需要再对sql进行调整. --1.查询对象 ...