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

    1.引入包 EntityFramework MySql.Data.Entity 2.配置文件 web.config <connectionStrings> <add name=&qu ...

  2. BIEE基本函数

    一,TRIM ,去除空字符 TRIM(EXPR) SUBSTRING("UT TIME"."月份" FROM 6 FOR 2) 1.AGGREGATE AT 此 ...

  3. unity3d使用litjson中文显示的问题

    我们在使用litjson时它的编码方式是unicode的,所以我将json转成string输出时显示的是unicode的编码.这样我们显示或者保存中文时不是很方便.我们可以将中文的unicode转成能 ...

  4. php error _report

    [error_reporting] => Array   (   [global_value] => 32767   [local_value] => 0   [access] =& ...

  5. Android使用Eclipse遇到"java.lang.ClassNotFoundException"

    最近遇到个Android Jar的问题,找了几天才找到root cause. 在此记录下. 我们的Android项目需要使用一个供应商的Jar. 我们使用的开发环境为:Eclipse + ADT插件( ...

  6. 一些Android经验

    1.如果在调试Android程序中,你非常确定你的代码是没有问题的,比如在跟Server交互时候,抓包软件抓到的包是正常的,但是在解析数据时候有问题, 你可以试着换个Android设备看看,模拟器换成 ...

  7. 安装Mysql,缺少libaio依赖

    安装mysql时报如下错误: xxxxx/mysql/bin/mysqld: error : cannot open shared object file: No such file or direc ...

  8. redis写shell与ssh免密码登陆

     redis-cli参数:-h :指定要连接的主机IP或域名-p :指定连接的端口-a :指定密码-r :执行指定的命令-n :数据库名-x :将最后一个参数输出为value redis写shell- ...

  9. HDU 1013 Digital Roots(字符串)

    Digital Roots Problem Description The digital root of a positive integer is found by summing the dig ...

  10. ios GCD的使用及封装

    实现代码: CGDHelper /* * Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法. * 系统要求:iOS4.0以上. */ #import & ...