即时通信系统中如何实现:支持PC端和移动端同时在线(即支持同帐号多设备同时登录)?

       如果我们开发的即时通信系统(IM系统)要支持同帐号多设备同时登录的场景(或称“多地登录”),即需要像QQ一样,在PC端登录的同时,也可以使用同一个帐号登录移动端(iOS或Android),那么,如何才能做到了?        

       在ESFramework/ESPlatform体系中,是使用 UserID 作为唯一标志来标记每一个用户的,也就是说,对于一个指定的UserID,只能有一个客户端在线。所以,ESFramework 虽然支持多种类型的客户端设备,但是,ESFramework并不支持不同类型的客户端设备同时登录同一个UserID。

       解决方案的原理是比较简单的:既然ESFramework要求UserID作为用户标记必须是唯一的,那么我们就引入一个称为“LoginID”的概念,对于同一个用户,在不同类型的设备上就使用不同的LoginID,但是这些LoginID都指向同一个真正的UserID。

一. LoginID 与 真正的UserID

1. 不需要支持同帐号多设备同时登录的简单场景

        在之前不支持同帐号多设备同时登录的场景中(简称“单设备登录”场景),登录用的帐号就是真正的UserID,也就是说ESFramework框架中各个API(各个方法以及事件)的参数涉及到的用户帐号都是真正的UserID。比如,一个帐号abc001,该帐号是存在于数据库的用户表中的;使用abc001登录到ESFramework服务器,ESFramework在整个的运作过程中,也是使用abc001来标记对应的客户端实例。在该场景中,不会存在多个运行的客户端实例都对应帐号abc001的情况。如果有个客户端已经使用abc001登录,然后再用该帐号在其它地方登录,默认的机制是会把之前登录的那个客户端挤掉线。

2. 需要支持同帐号多设备同时登录的复杂场景

       如果现在我们要支持同帐号多设备同时登录的场景(简称“多设备登录”场景),那么,ESFramework在整个的运作过程中,就不能使用abc001来标记对应的客户端实例了,因为存在多个客户端实例都对应同一个abc001帐号的情况。于是,我们使用LoginID来区分这种情况下不同的客户端实例。

       常用的方法是,在真正的UserID前加上两个字符的前缀以构成LoginID。 比如,对于abc001这个帐号,在使用iOS设备登录时,我们选择使用前缀“1#”,这样iOS设备使用的LoginID就是1#abc001;同理,Android设备就使用2#abc001

        该两个字符的前缀的含义是这样的:

(1)第二个字符“#”,是一个标志(token),表示该ID是一个LoginID。

(2)第一个字符,表示设备的类型。比如“0”表示.NET设备(PC),“1”表示iOS设备,“2”表示Android设备,等等。

       当使用LoginID后,ESFramework在整个的运作过程中就不再是使用真正的UserID来标记客户端实例了,而是使用LoginID -- 也就是说,ESFramework框架中各个API(各个方法以及事件)的参数涉及到的用户帐号都是LoginID了。        

二. MultiDeviceHelper 类

        ESFramework.Boost 类库中提供了MultiDeviceHelper类,用于为多设备同时登录提供支持。特别是,提供了与LoginID的构造和解析相关的API。

        在MultiDeviceHelper的静态构造函数中,规定了每种设备的前缀,如下所示:

    static MultiDeviceHelper()
    {
        #region 如果在当前的应用中,不存在某种类型的设备,则注释掉下面对应的语句即可。             MultiDeviceHelper.LoginIDPrefixMapping.Add(ClientType.IOS, "1#");
        MultiDeviceHelper.LoginIDPrefixMapping.Add(ClientType.Android, "2#");
        MultiDeviceHelper.LoginIDPrefixMapping.Add(ClientType.WebSocket, "3#");
        MultiDeviceHelper.LoginIDPrefixMapping.Add(ClientType.WindowsPhone, "4#"); 
        #endregion
    }

         然后, MultiDeviceHelper提供了多个静态方法以完成真正UserID、设备类型与LoginID之间的转换:

      即时通信系统中如何实现:支持PC端和移动端同时在线(即支持同帐号多设备同时登录)?_第1张图片 

三. 登录和登录验证

       客户端在登录时会调用IRapidPassiveEngine的Initialize方法:

       LogonResponse Initialize(string userID, string logonPassword, string serverIP, int serverPort, ICustomizeHandler customizeHandler); 

       该方法的第一个参数就需要传入LoginID,比如 1#abc001。

       在服务端会回调IBasicHandler接口的VerifyUser方法来进行帐号密码验证:

        bool VerifyUser(string systemToken, string userID, string password, out string failureCause);        

       此时要注意的是,VerifyUser方法传入的userID参数实际上是LoginID,即 1#abc001。我们需要通过调用MultiDeviceHelper的ParseLoginID方法来获取真正的UserID,该方法会返回 abc001,并且out参数指明设备类型为iOS。

四. 处理消息及其它

       在ESFramework架构中,服务端是通过回调ICustomizeHandler接口的HandleInformation方法来处理接收到的消息的:

       void HandleInformation(string sourceUserID, int informationType, byte[] info); 

       同上面一样,此处的sourceUserID参数实际上也是LoginID,所以,也需要调用MultiDeviceHelper的ParseLoginID方法来将其转换成真正的UserID。

       同理,在多设备登录场景中,ESFramework框架中各个API(各个方法以及事件)的userID参数实际上都是LoginID,在处理时都需要做类似的处理,这里就不一一列举了。

五. 多设备聊天消息同步

       在解决了多设备同时登录的问题后,还有一个常见的需求:类似QQ的PC和手机端同时在线时,别人给我发一条消息,手机端和PC端都能接收到。这样的功能是怎么实现的了?

       在单设备登录场景中,我们通常是在客户端调用ICustomizeOutter接口的下列Send方法来发送聊天消息的:

       void Send(string targetUserID, int informationType, byte[] info); 

       该方法的第一个参数是接收者的UserID,表示直接将聊天消息发送给对方(可能是经过服务器中转,或者是经P2P通道直接传送)。

       但是,在多设备登录场景中,不能再直接发送了,而是必须要经过服务器中转,通过调用下面的Send方法:

       void Send(int informationType, byte[] info); 

       该Send方法将消息直接发送给服务端,在info参数中包含要消息接收者的UserID。服务端在处理该消息时,需要从info中将接收者UserID解析出来,然后,调用MultiDeviceHelper 的 GetLoginIDList 方法来获取各个设备类型对应的LoginID,然后,服务端在把该消息发送给每一个LoginID。如此,手机端和PC端就都能收到这条聊天消息了。 


关于如何使用 ESFramework 通信框架,可以参见ESFramework开发手册。

你可能感兴趣的:(即时通讯,移动端,多地登录,多设备登录)