请选择 进入手机版 | 继续访问电脑版

默认
发表评论 32
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
[已回复] MobileIMSDK服务端的多设备登陆互踢问题求助
同一个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
哥你太敷衍了,标题就4个字,还把4个字中的一个给打错了。。
WX20170714-150704@2x.png
引用:JackJiang 发表于 2017-07-14 15:07
哥你太敷衍了,标题就4个字,还把4个字中的一个给打错了。。

签名: 该会员没有填写今日想说内容.
不理解什么是快速登陆。

你可以在客户端收到被踢指令时立即调用sedLoginout指令退出网络。
引用:JackJiang 发表于 2017-07-14 15:14
不理解什么是快速登陆。

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

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

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

但如果设备1被设备2踢下来后,隔几秒钟重新登陆,互踢就一切正常。
签名: 该会员没有填写今日想说内容.
引用:tiandao 发表于 2017-07-14 15:18
但如果设备1被设备2踢下来后,隔几秒钟重新登陆,互踢就一切正常。

被踢这端的客户端后台在收到指令立即调用sendLoginout登出指令,不可能还会重新登陆,你去试试
引用: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消息链接还没有建立,然后立马要被踢下线,导致服务器发过来的下线指令没有收到。出现了上面的消息发送失败的情况。
签名: 该会员没有填写今日想说内容.
引用:tiandao 发表于 2017-07-14 15:44
当出现互踢失败的时候
服务器这边出现这些信息
- [15:43:22.212]toSession==null >> id=0的用户尝试发 ...

你不能在回调里发送踢出指令,因为在这一层存储的用户在线列表(key=uid、value=socketsession)是用用户id作为key存储的,那么在回调里的时候已经由后一个用户覆盖了前一个用户在列表中的sessionsocket了。

你应该在OnlineProcessor的putUser方法中我留的“TODO”地方来按你的互踢逻辑来处理,我已经留好了位置,见下图:
aa.png
引用:JackJiang 发表于 2017-07-14 16:02
你不能在回调里发送踢出指令,因为在这一层存储的用户在线列表(key=uid、value=socketsession)是用用户 ...

搜嘎,我去研究up的最新版
签名: 该会员没有填写今日想说内容.
引用:JackJiang 发表于 2017-07-14 15:14
不理解什么是快速登陆。

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

请问下, 我在V3版mobileimsdk实现同一账号多设备登录踢调功能遇到的问题

问题1:    我在客户端调用sendLoginout后,新登录的设备也会掉线(之后会再重连),怎么解决?

服务端代码:
	//TODO 同一账号的重复登陆情况可在此展开处理逻辑
			try {
				LocalSendHelper.sendData(session,ProtocalFactory.createCommonData(
						"OUT", "0", user_id, false, null, 5));
			} catch (Exception e) {
				// TODO 尚未处理异常
				e.printStackTrace();
			}


客户端代码
@Override
	public void onTransBuffer(String fingerPrintOfProtocal, String userid, String dataContent, int typeu)
	{
		Log.d(TAG, "【DEBUG_UI】[typeu="+typeu+"]收到来自用户"+userid+"的消息:"+dataContent);

		if(mainGUI != null)
		{
            if(dataContent.equals("OUT")){
                mainGUI.doLogout();
            }else {
                Toast.makeText(mainGUI, userid+"说:"+dataContent, Toast.LENGTH_SHORT).show();
                this.mainGUI.showIMInfo_black(userid+"说:"+dataContent);
            }
		}
	}

引用:kelefun 发表于 2017-07-16 20:59
请问下, 我在V3版mobileimsdk实现同一账号多设备登录踢调功能遇到的问题

问题1:    我在客户端调用sen ...

你详细理解一下我在10楼的回答。同一账号和重复登陆问题你需要自已去实现相关的逻辑(在UserProcessor里修改),至于你是基于什么样的逻辑完全可以自行决定。
引用:JackJiang 发表于 2017-07-16 22:09
你详细理解一下我在10楼的回答。同一账号和重复登陆问题你需要自已去实现相关的逻辑(在UserProcessor里 ...

谢谢回复,我想要的逻辑是,同一账号只能在一个设备登录,后登录的把之前登录的踢掉 (新登录的设备无感知).
我看了10楼的您的回复了,我是在OnlineProcessor里中putUser方法您的TODO注释中 添加的退出指令(推送普通消息)然后客户端收到推送内容判断是否是退出,然后调用退出方法
                                try{
                                        code = LocalUDPDataSender.getInstance(MainActivity.this).sendLoginout();
                                }
                                catch (Exception e){
                                        Log.w(TAG, e);
                                }
                                IMClientManager.getInstance(MainActivity.this).resetInitFlag();
                                return code;


实际效果就是新登录的设备也会退出一次,之后再重连
看了下源码,OnlineProcessor中putUser被调用之时,新登录的session已经建立了(存了同样的user_id)
所以在putUser方法或在onUserLoginAction_CallBack中进行重复登录逻辑处理没有什么区别,不知道这样理解是否正确?
你提供的LogicProcessor源码--processLogin方法
                                {
                                        session.setAttribute(OnlineProcessor.USER_ID_IN_SESSION_ATTRIBUTE, loginInfo.getLoginUserId());
                                        OnlineProcessor.getInstance().putUser(loginInfo.getLoginUserId(), session);
                                        
                                        serverCoreHandler.getServerEventListener().onUserLoginAction_CallBack(
                                                        loginInfo.getLoginUserId(), loginInfo.getExtra(), session);
                                }


Ps:没有找到你说的UserProcessor在哪.

引用:tiandao 发表于 2017-07-14 16:27
搜嘎,我去研究up的最新版

你好,你实现功能了吗?能否贴个示例代码?
引用:kelefun 发表于 2017-07-17 09:38
谢谢回复,我想要的逻辑是,同一账号只能在一个设备登录,后登录的把之前登录的踢掉 (新登录的设备无感知).
...

UserProcessor只在MobileIMSDK v2版里有,在v3里对应的是OnlineProcessor,我说错了。

我有空了在下一个版本实现一个互踢的参考逻辑吧,不过现在你可以这样去改试试:

1)当第2个客户端(同一个账号)登陆时,服务端在OnlineProcessor里立即像这个socket推出一条“被踢”指令,同时立即断开此socket(你可以测试一下,如果立即断开socket会导致指令还没能发到客户就断开的话,就稍等个几毫秒再断开此socket)并在OnlineProssor里清掉这个已被断掉的socket;
2)客户端在收到“被踢”指令后,不发sendLoginout指令,但ClientCoreSDK.release()方法是一定要调用的:目的是关掉客户端正在运行的im后台线程和网络监听。

你按我的思路试试看。
引用:JackJiang 发表于 2017-07-17 10:20
UserProcessor只在MobileIMSDK v2版里有,在v3里对应的是OnlineProcessor,我说错了。

我有空了在下一 ...

非常希望您能提供一个实现互踢逻辑的demo.

我之前有试过,没有达到效果,(刚接触这个sdk没多久,理解的不是很透)

遇到的问题 1:  服务器主动断开之前登录的socket,如何能保证旧设备收到"被踢"指令(以便Release---释放客户端监听)?
问题2:如果想要不影响新登录的账号,应该在建立新的session之前,处理掉之前旧设备的session,不知道如何做到
问题3:有想过把之前设备登录的userId重命名,然后让它自己慢慢处理退出指令,不知道能不能这样做?

总之 还是希望您能提供一个demo
引用:kelefun 发表于 2017-07-17 10:56
非常希望您能提供一个实现互踢逻辑的demo.

我之前有试过,没有达到效果,(刚接触这个sdk没多久,理解的不 ...

按我16搂的思路理论上是可以实现的。你的问题3里的想法是一个思路,但是会把问题复杂化,没有必要。

其实MINA内部本来就是一条连接一个session(就是socket句柄了),OnlineProcessor只是MobileIMSDK加的在线列表逻辑而已,也就是说你只要针对某个sesion进行操作,它的消息一定可以发过去,不会影响别的连接。
另外,旧的session你可以关掉它,MINA有api,Mobileimsdk里也有关闭的代码,你看看就明白了。这些并没有你想象的复杂。

最佳实践一定是优雅而简单的,如果你觉得复杂,那一定是还没有理解透,那应该换个思路。
引用: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个设备在很短时间内相继重登陆,会出现不走这个函数的情况。太诡异了


签名: 该会员没有填写今日想说内容.
引用:tiandao 发表于 2017-07-18 15:48
try {
                                IoSession oldsession = onlineSessions ...

解决了吗?
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部