默认
发表评论 7
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
[已解决] 请问MobileIMSDK服务端发生kickout时,具体回调逻辑是怎样?
是这样的,现在我把集成SDK的应用程序部署在本地和远程LINUX服务器测试时,在KickOut发生时,两个环境对于onUserLoginSuccess和onUserLogout的回调情况是不一样的。
在本地测试环境下,我先用安卓手机请求登录,然后再用IOS手机请求登录同一个账号,发生kickout,同时只回调了onUserLoginSuccess。
在远程LINUX环境下,还是先用安卓手机请求登录,然后再用IOS手机请求登录同一个账号,发生kickout,这时会先调用onUserLogout然后再调用onUserLoginSuccess。
请问正常情况下发生KickOut时,是不是不会回调onUserLogout的?如果会回调,那么当发生KickOut时,这个回调的规律大概是怎样的?
求教,万分感谢

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

上一篇:[已回复] MobileIMSDK选用WebSocket是否可以不开启TCP和 UDP?下一篇:[已回复] 关于MobileIMSDK服务端集群的实现思路问题

本帖已收录至以下技术专辑

推荐方案
评论 7
这个互踢逻辑是比较简单的,原理就是:
当新登陆时,服务端检查到之前已有登陆,就会向之前的会话发送被踢指令,被踢者收到指令后,执行本地的断开命令,并释放网络资源。

如果服务端的这个onLoginOut的被调用,那应该就是在被踢指令收到后,客户端又显示调用了sendLoginout指令,这应该是没有必要的,你检查一下,是否存在这种调用,如果存在,你就取消就好了,不需要的。

如果存在什么代码的疑问,你就贴出来具体的代码,我来给你解答
引用:JackJiang 发表于 2022-01-13 16:43
这个互踢逻辑是比较简单的,原理就是:
当新登陆时,服务端检查到之前已有登陆,就会向之前的会话发送被踢 ...

好的,所以说正常情况下,发生KickOut事件时,onUserLogout就应该是不会被调用的对吧?
引用:荣K 发表于 2022-01-13 17:43
好的,所以说正常情况下,发生KickOut事件时,onUserLogout就应该是不会被调用的对吧?

我记错了,是有可能会被调用的,你读一下ServerCoreHanler这个类里的sessionClose方法的代码:

尤其注意这段“if(sessionInOnlinelist != null && session != null && session == sessionInOnlinelist)”中的“session == sessionInOnlinelist”这个条件!
    /**
     * 框架中,当用户的会话被关闭时将调本本方法。
     * <p>
     * 本方法中会将此用户从在线列表及相关队列中移除,将通过回调通知上层代码(由
     * 上层代码接力实现自定义的其它业务处理)。
     * <p>
     * <b>会话被关闭的可能性有3种:</b>
     * <ul>
     *   <li>1)当客户端显式地退出网络连接时(即正常退出时);</li>
     *   <li>2)客户端非正常关闭,但服务端的会话超时到来时;</li>
     *   <li>3)与客户端的会话发生其它错误或异常时。</li>
     * </ul>
     * <p>
     * 本方法将被 {[url=home.php?mod=space&uid=5196]@link[/url] net.x52im.mobileimsdk.server.network.tcp.MBTCPClientInboundHandler#channelInactive(
     * io.netty.channel.ChannelHandlerContext)}调用,以便接受Netty中客户端“会话”断开通知。
     * 
     * @param session 被关闭的会话Channel引用
     * @throws Exception 任何错误发生时将抛出本异常
     * @see net.x52im.mobileimsdk.server.processor.OnlineProcessor#removeUser(int)
     * @see net.x52im.mobileimsdk.server.event.ServerEventListener#onUserLogoutAction_CallBack(int, Object)
     * @see net.x52im.mobileimsdk.server.network.tcp.MBTCPClientInboundHandler#channelInactive(io.netty.channel.ChannelHandlerContext)
     */
    public void sessionClosed(Channel session) throws Exception 
    {
            // 取出在连接认证时放入会话中的user_id
            String user_id = OnlineProcessor.getUserIdFromChannel(session);
            
            if(user_id != null)
            {
                    // 从在线列表中取出会话引用
                    Channel sessionInOnlinelist = OnlineProcessor.getInstance().getOnlineSession(user_id);
                    
                    logger.info("[IMCORE-{}]{}的会话已关闭(user_id={}, firstLoginTime={})了..."
                                    , Gateway.$(session), ServerToolKits.clientInfoToString(session), user_id, OnlineProcessor.getFirstLoginTimeFromChannel(session));
                    
                    // TODO just for DEBUG:以下代码仅作Debug之用,您随时可删除之!
                    {// DEBUG Start
                            
                            logger.info(".......... 【0】[当前正在被关闭的session] session.hashCode={}, session.ip+port={}"
                                            , session.hashCode(), session.remoteAddress());
                            
                            if(sessionInOnlinelist != null)
                            {
                                    logger.info(".......... 【1】[处于在线列表中的session] session.hashCode={}, session.ip+port="
                                                    , sessionInOnlinelist.hashCode(), sessionInOnlinelist.remoteAddress());
                            }
                    }// DEBUG END
            
                    //## Bug FIX: 20171211 START
                    // [此bug的现象是]:客户端在某种几小几率下出现每隔21秒的周期性掉线问题。原因是它的当前会话在
                    // 它前一个被废弃的会话(可能是客户端网络原因)超时后错误地将当前会话从在线列表移除而导致
                    // 的。加上此判断后,意味着被close的会话要从在线列表中移除时必须保证移除的是该会话本身,这
                    // 样就排除了客户端在极端网络情况下发起的新会话不会因此废弃的会话超时时而把新会话错误地从在
                    // 线列表中移除的问题,从而解决此bug。
                    //
                    // [产生此bug的根本原因是]:在线列表中的key是user_id,而同一个user_id发起的新会话,在在线列表
                    // 中被放入时的逻辑时只覆盖之前的会话,而未close掉(之所以这么做是为了方便以后做多点登陆功能),
                    // 而且在线列表就这么实现的话,当前来说并没有什么问题。
                    if(sessionInOnlinelist != null && session != null && session == sessionInOnlinelist)
                    //## Bug FIX: 20171211 END
                    {
                            // 尽最大可能移除用户登陆成功后暂存到会话对象中的user_id
                                OnlineProcessor.removeAttributesForChannel(session);
                            
                            // 从在线列表中移除
                            // 【理论上:】因为每个session只在用户登陆成功后才会放入列表中,那么每
                            //         一个存放在在线列表中的session肯定都对应了user_id。所以
                            //                    此处先取出session中之前存放的id再把这个session从在线列表中删除
                            //        的算法是可以保证session被关闭的同时肯定能同步将它从在线列表中移除,
                            //        从而保证在列表的准确性!
                            OnlineProcessor.getInstance().removeUser(user_id);

                            // 开始回调
                            if(serverEventListener != null)
                                    // 通知回调:用户退出登陆了
                                    serverEventListener.onUserLogout(user_id, null, session);
                            else
                                    logger.debug("[IMCORE-{}]>> 会话{}被系统close了,但回调对象是null,没有进行回调通知."
                                                    , Gateway.$(session), ServerToolKits.clientInfoToString(session));
                    }
                    else
                    {
                            logger.warn("[IMCORE-{}]【2】【注意】会话{}不在在线列表中,意味着它是被客户端弃用/或被服务端强踢,本次忽略这条关闭事件即可!"
                                            , Gateway.$(session), ServerToolKits.clientInfoToString(session));
                    }
            }
            else
            {
                    logger.warn("[IMCORE-{}]【注意】会话{}被系统close了,但它里面没有存放user_id,它很可能是没有成功合法认证而被提前关闭,从而正常释放资源。"
                                    , Gateway.$(session), ServerToolKits.clientInfoToString(session));
            }
    }


也就是说,当kickOut时,被踢者执行断开指令,然后server端这边,如果getOnlineSession拿到的session就是当前要断开的session,那么就会触发onUserLogout。
可是我不希望在kickOut发生时,执行上层实现的onUserLogout中的一些逻辑,有没有什么办法,可以在实现的onUserLogout中准确判断,这次onUserLogout回调是被踢了才触发的?
引用:荣K 发表于 2022-01-14 13:23
也就是说,当kickOut时,被踢者执行断开指令,然后server端这边,如果getOnlineSession拿到的session就是当 ...

不能。除非在sdk中,判定被踢的socket时,给它加一个属性标记,在这里close时读取标记才行。要不我来改一下sdk代码,晚点给你测试
SDK已经改好了,用这个jar替换到你的服务端工程中:
MobileIMSDKServer.jar.zip (93.88 KB , 下载次数: 1 )

onUserLogout回调方法中现在加了一个参数:
/**
 * 用户退出登录回调方法定义(可理解为下线通知回调)。
 * <p>
 * 服务端的应用层通常可在本方法中实现用户下线通知等。
 * 
 * @param userId 下线的用户user_id
 * @param obj
 * @param session 此客户端连接对应的 netty “会话”
 * @param beKickoutCode 被踢原因编码,本参数当为-1时表示本次logout事件不是源自“被踢”,否则被踢原因编码请见 PKickoutInfo类中的常量定义
 * @see {@link OnlineProcessor#setBeKickoutCodeForChannel(Channel, int)}
 */
 void onUserLogout(String userId, Object obj, Channel session, int beKickoutCode);

参数beKickoutCode的值:PKickoutInfo类中的常量定义!
引用:JackJiang 发表于 2022-01-14 16:22
SDK已经改好了,用这个jar替换到你的服务端工程中:

经楼主验证,以上SDK修改可以达到目的:
[已解决] 请问MobileIMSDK服务端发生kickout时,具体回调逻辑是怎样?_QQ截图20220117161514.png

有需要的可以直接在github或gitee上下载 MobileIMSDK 的v6.2及更新版本即可:
https://github.com/JackJiang2011/MobileIMSDK
https://gitee.com/jackjiang/MobileIMSDK
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部