默认
发表评论 32
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
[已回复] MobileIMSDK服务端的多设备登陆互踢问题求助
阅读(83261) | 评论(32 收藏 淘帖1
同一个ID用户登录到两台设备时,我在onVerifyUserCallBack 返回前,
        public int onVerifyUserCallBack(String lpUserName, String lpPassword, String extra)
        {
                logger.debug("正在调用回调方法:OnVerifyUserCallBack...(extra="+extra+")");
                logger.debug("正在调用回调方法:OnVerifyUserCallBack...(lpUserName="+lpUserName+")");
                logger.debug("正在调用回调方法:OnVerifyUserCallBack...(lpPassword="+lpPassword+")");                
                HashMap<Integer, String> map= UserProcessor.getInstance().getUserNames();
                Iterator iter = map.entrySet().iterator();
                while (iter.hasNext()) {
                        Map.Entry entry = (Map.Entry) iter.next();
                        Integer key = (Integer)entry.getKey();
                        String val = (String)entry.getValue();
                        if(val.equals(lpUserName)){
                                try {
                                        ServerLauncher.sendData(0, key , "logout");
                                } catch (Exception e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                }
                                break;
                        }
                }
                return 0;
        }

遍历了UserProcessor.getInstance().getUserNames()和lpUserName,存在key就给对应的发送ServerLauncher.sendData(0, key , "logout");下线指令。
现在遇到的问题:2个设备快速切换登陆的时候,会出现互踢失败的情况,然后两台设备会不停的断线登录。

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

标签:MobileIMSDK
上一篇:[已解决] MobileIMSDK 安卓客户端退出登入后重新登入问题下一篇:[已回复] 求助MobileIMSDK v2版中掉线后自动重登录的问题

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

推荐方案
评论 32
引用:JackJiang 发表于 2017-07-14 15:07
哥你太敷衍了,标题就4个字,还把4个字中的一个给打错了。。

签名: 该会员没有填写今日想说内容.
引用:JackJiang 发表于 2017-07-14 15:14
不理解什么是快速登陆。

你可以在客户端收到被踢指令时立即调用sedLoginout指令退出网络。

就是设备1被设备2踢下来后,立刻重新登陆,就会导致互踢失效。
签名: 该会员没有填写今日想说内容.
引用:JackJiang 发表于 2017-07-14 15:14
不理解什么是快速登陆。

你可以在客户端收到被踢指令时立即调用sedLoginout指令退出网络。

但如果设备1被设备2踢下来后,隔几秒钟重新登陆,互踢就一切正常。
签名: 该会员没有填写今日想说内容.
引用:JackJiang 发表于 2017-07-14 15:19
被踢这端的客户端后台在收到指令立即调用sendLoginout登出指令,不可能还会重新登陆,你去试试

我手动快速重新登陆,会出现问题的啊
(void)loginON{
    //应用登陆成功后,调用SDK
    __weak ViewController *safeSelf = self;
    // 准备好异步登陆结果回调block(将在登陆方法中使用)
    self.hud.label.text = NSLocalizedString(@"数据初始化中。。", @"HUD loading title");
    self.onLoginSucessObserver = ^(id observerble ,id data) {
        // * 已收到服务端登陆反馈则当然应立即取消显示登陆进度条
        [safeSelf.hud hideAnimated:YES afterDelay:1.];
        // 服务端返回的登陆结果值
        int code = [(NSNumber *)data intValue];
        // 登陆成功
        if(code == 0){
            sleep(1);
            [safeSelf _pushMainControllerAnimated:YES];
        }
    };
    
    //** 设置服务器地址和端口号
    NSString *serverIP = @"192.168.2.101 

";//[self.addrField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    NSString *serverPort = @"7901";//self.portField.text;
    //        int serverPort = [self.portField.text intValue];;
    if(!([serverIP length] <= 0)
       && !([serverPort length] <= 0))
    {
        // 设置好服务端的连接地址
        [ConfigEntity setServerIp:serverIP];
        // 设置好服务端的UDP监听端口号
        [ConfigEntity setServerPort:[serverPort intValue]];
    }
    
    //** 登陆名和密码
    NSString *loginNameStr = self.username.text;
    NSString *loginPswStr = self.password.text;
    
    //** 向服务端发送登陆信息
    [self doLoginImpl:loginNameStr withPassword:loginPswStr];
}
/*
* 真正的登陆信息发送实现方法。
*/
- (void)doLoginImpl: (NSString *)loginNameStr withPassword: (NSString *)loginPswStr
{
    // * 设置好服务端反馈的登陆结果观察者(当客户端收到服务端反馈过来的登陆消息时将被通知)
    [[[IMClientManager sharedInstance] getBaseEventListener] setLoginOkForLaunchObserver:self.onLoginSucessObserver];
    
    // * 发送登陆数据包(提交登陆名和密码)
    int code = [[LocalUDPDataSender sharedInstance] sendLogin:loginNameStr withPassword:loginPswStr];
    NSLog(@"%d\n",code);
}

self.onLoginSucessObserver = ^(id observerble ,id data) {
        // * 已收到服务端登陆反馈则当然应立即取消显示登陆进度条
        [safeSelf.hud hideAnimated:YES afterDelay:1.];
        // 服务端返回的登陆结果值
        int code = [(NSNumber *)data intValue];
        // 登陆成功
        if(code == 0){
            sleep(1);
            [safeSelf _pushMainControllerAnimated:YES];
        }
    };

立刻重新登陆,这个返回是成功的啊
签名: 该会员没有填写今日想说内容.
引用:JackJiang 发表于 2017-07-14 15:19
被踢这端的客户端后台在收到指令立即调用sendLoginout登出指令,不可能还会重新登陆,你去试试

当出现互踢失败的时候
服务器这边出现这些信息
[INFO] - [15:43:22.212][IMCORE]toSession==null >> id=0的用户尝试发给客户端200004的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息可考虑作离线处理哦). | (ServerCoreHandler^sendData:686)
[INFO] - [15:43:25.202][IMCORE]toSession==null >> id=0的用户尝试发给客户端200004的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息可考虑作离线处理哦). | (ServerCoreHandler^sendData:686)
[INFO] - [15:43:28.208][IMCORE]toSession==null >> id=0的用户尝试发给客户端200004的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息可考虑作离线处理哦). | (ServerCoreHandler^sendData:686)
[INFO] - [15:43:31.203][IMCORE]toSession==null >> id=0的用户尝试发给客户端200004的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息可考虑作离线处理哦). | (ServerCoreHandler^sendData:686)
好像是服务器给200004发送下线指令失败了。
我觉得原因是:客户端1重新登陆太快了,导致另一个客户端2消息链接还没有建立,然后立马要被踢下线,导致服务器发过来的下线指令没有收到。出现了上面的消息发送失败的情况。
签名: 该会员没有填写今日想说内容.
引用:JackJiang 发表于 2017-07-14 16:02
你不能在回调里发送踢出指令,因为在这一层存储的用户在线列表(key=uid、value=socketsession)是用用户 ...

搜嘎,我去研究up的最新版
签名: 该会员没有填写今日想说内容.
引用:JackJiang 发表于 2017-07-17 11:37
按我16搂的思路理论上是可以实现的。你的问题3里的想法是一个思路,但是会把问题复杂化,没有必要。

...

public void putUser(String user_id, IoSession session)
        {
                if(onlineSessions.containsKey(user_id))
                {
                        logger.debug("[IMCORE]【注意1】用户id="+user_id+"已经在在线列表中了,session也是同一个吗?"
                                        +(onlineSessions.get(user_id).hashCode() == session.hashCode()));
                        logger.debug("[IMCORE]【注意2】用户id="+user_id+onlineSessions.get(user_id)+session);
                        try {
                                IoSession oldsession = onlineSessions.get(user_id);
                                logger.debug("-->发送结果:"+LocalSendHelper.sendData(oldsession,ProtocalFactory.createCommonData(
                            "logout", "0", user_id, false, null, 5)));
                                oldsession.close(true);
                                onlineSessions.remove(user_id);
                        } catch (Exception e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                        // TODO 同一账号的重复登陆情况可在此展开处理逻辑
                }
               
                onlineSessions.put(user_id, session);
               
                __printOnline();// just for debug
        }
发生了奇怪的事情,有些时候能够成功互踢,有些时候会把自己给T下来(自己登陆成功后几秒钟自己收到了logout下线指令,但这个指令是发给另一个设备的),另一个账号T不下来。还有为什么互踢的时候每次都会出现下面这个情况
[INFO] - [15:51:43.512][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)
[INFO] - [15:51:46.511][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)
[INFO] - [15:51:49.511][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)
[INFO] - [15:51:52.515][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)
[INFO] - [15:51:55.514][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)
而且2个设备在很短时间内相继重登陆,会出现不走这个函数的情况。太诡异了


签名: 该会员没有填写今日想说内容.
引用:kelefun 发表于 2017-07-17 09:39
你好,你实现功能了吗?能否贴个示例代码?

没实现呢,发生了奇怪的事情
签名: 该会员没有填写今日想说内容.
引用:JackJiang 发表于 2017-07-18 15:52
解决了吗?

[INFO] - [15:51:43.512][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)
[INFO] - [15:51:46.511][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)
[INFO] - [15:51:49.511][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)
[INFO] - [15:51:52.515][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)
[INFO] - [15:51:55.514][IMCORE]toSession==null >> id=0的用户尝试发给客户端yangqj的消息:str={}因接收方的id已不在线,此次实时发送没有继续(此消息应考虑作离线处理哦). | (LocalSendHelper^sendData:86)在另一个设备重登陆的时候,为什么要调用完这5次,才会再次调用public void putUser(String user_id, IoSession session) ,在上面全部调用完前登陆的话,会把自己给T下来,但是等上面5次重发送结束之后,互踢就一切正常了
签名: 该会员没有填写今日想说内容.
引用:tiandao 发表于 2017-07-18 15:48
public void putUser(String user_id, IoSession session)
        {
                if(onlineSessio ...

互踢解决:  第一步:        public void putUser(String user_id, IoSession session)
    {
            if(onlineSessions.containsKey(user_id))
            {
                    logger.debug("[IMCORE]【注意】用户id="+user_id+"已经在在线列表中了,session也是同一个吗?"
                                    +(onlineSessions.get(user_id).hashCode() == session.hashCode()));
                    try {
                        IoSession oldsession = onlineSessions.get(user_id);
                        logger.debug("-->发送结果:"+LocalSendHelper.sendData(oldsession,ProtocalFactory.createCommonData(
                                        "logout", "0", user_id, false, null, -1)));
                        oldsession.close(true);
                    } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                    }
                    // TODO 同一账号的重复登陆情况可在此展开处理逻辑
            }

            onlineSessions.put(user_id, session);

            __printOnline();// just for debug
    }  第二步:public void sessionClosed(IoSession session) throws Exception
    {
            String user_id = OnlineProcessor.getUserIdFromSession(session);
            logger.info("[IMCORE]与"+ServerToolKits.clientInfoToString(session)+"的会话关闭(user_id="+user_id+")了...");
            if(user_id != null)
            {
                    logger.info("[是否相同]"+OnlineProcessor.getInstance().getOnlineSession(user_id)+session);
                    if(OnlineProcessor.getInstance().getOnlineSession(user_id).hashCode() == session.hashCode())
                            OnlineProcessor.getInstance().removeUser(user_id);
                    
                    if(serverEventListener != null)
                            serverEventListener.onUserLogoutAction_CallBack(user_id, null, session);
                    else
                            logger.debug("[IMCORE]>> 客户端"+ServerToolKits.clientInfoToString(session)+"的会话被系统close了,但回调对象是null,没有进行回调.");
            }
            else
            {
                    logger.warn("[IMCORE]【注意】客户端"+ServerToolKits.clientInfoToString(session)+"的会话被系统close了,但它里面没有存放user_id,这个会话是何时建立的?");
            }
    }
修改ServerCoreHandler.java文件上面这个函数
OnlineProcessor.getInstance().removeUser(user_id);
改为
                    if(OnlineProcessor.getInstance().getOnlineSession(user_id).hashCode() == session.hashCode())
                            OnlineProcessor.getInstance().removeUser(user_id);

签名: 该会员没有填写今日想说内容.
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部