Mina断线重连时出现DeadLock,死锁解决方案

Mina客户端断线重连,死锁异常DEAD LOCK: IoFuture.await() was invoked from an I/O processor thread. Please use IoFutureListener or configure a proper thread model alternatively. 解决!

最近在看mina框架,客户端与服务器端实现长连接,与断线重连,这些网络上其他博客都有很详细的介绍,我也是看这些前辈的博客才有渠道去认识与了解mina框架,所以心存感激.

学习mina的路上遇到了这个死锁问题困扰了很久,网上介绍的基本上是死锁检测,( ( ̄▽ ̄)~*检测出来有啥用,我想要解决啊!),查询无果只能自己查原因,然后百度翻译一下报的这个死锁异常,意思是:” 锁死:iofuture.await()从I/O处理器线程调用。请用iofuturelistener或配置适当的线程模型”,我自己理解了一下,他这个意思就是叫你创建一个监听来监听连接或者创建一个线程来连接,我一开始是创建监听连接,但是发现仍然会出现死锁,具体我也不清楚,没有继续深入,但是创建线程连接是可行的

我选用重连方式是监听器方式:具体重连方式在: http://chwshuang.iteye.com/blog/2028951

话不多说,贴代码:

第一个是连接管理者:ConnectionManager.java

package view.my.ad.connector;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;

import org.apache.mina.core.RuntimeIoException;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.concurrent.Executors;

import view.my.ad.thread.ClientHandler;
import view.my.ad.thread.ConnectionThread;
import view.my.ad.utils.IoListener;
import view.my.ad.utils.ServerUtil;

public class ConnectionManager {

    private static final String TAG = "ZZHConnectionManager";
    //创建Socket连接对象
    private NioSocketConnector connector;
    //创建服务器地址对象
    private InetSocketAddress address;
    private Context mContext;
    private ConnectFuture future;

    /**
     * 构造
     * @param
     */
    public ConnectionManager(Context context){
        mContext= context;
        init();
    }

    private void init() {
        //获取地址
        address=new InetSocketAddress(ServerUtil.SERVER_IP,ServerUtil.SERVER_PORT);
        //初始化连接对象
        connector=new NioSocketConnector();
        //配置连接参数
        connector.getSessionConfig().setReadBufferSize(ServerUtil.SERVER_ReadBufferSize);
        connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
        connector.getFilterChain().addLast("exceutor", new ExecutorFilter());
        connector.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
        connector.getFilterChain().addLast("codec",
                new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"),
                        LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue())));
        //设置超时
        connector.setConnectTimeoutCheckInterval(ServerUtil.SERVER_ConnectionTimeout);
        connector.setHandler(new ClientHandler());
        connector.setDefaultRemoteAddress(address);
        connector.addListener(new IoListener() {
            @Override
            public void sessionDestroyed(IoSession ioSession) throws Exception {
                super.sessionDestroyed(ioSession);
                Log.e(TAG,"断开连接,开启连接线程,正在尝试重新连接......" );
                ConnectionThread thread=new ConnectionThread(mContext);
                thread.start();
                //直接调用仍然会出现异常
                //CheckConnect();
            }
        });
    }
    /**
     * 与服务器连接的方法
     * 连接过程中可能抛出的各种异常
     */
    public void CheckConnect(){
        Log.e(TAG, "CheckConnect: 正在准备连接服务器......");
            try {
                Log.i(TAG, "CheckConnect: 正在检查网络配置......");
                if (CheckNetWork(mContext)){
                    Log.e(TAG, "CheckConnect: 网络正常,尝试连接......" );
                    future=connector.connect(address);
                    //等待连接创建成功
                    future.awaitUninterruptibly();
                }else{
                    Log.e(TAG, "CheckConnect: 网络异常,10秒后再次启动连接......");
                    Thread.sleep(10000);
                    SessionManager.getInstance().removeSession();
                }
            }catch (IllegalStateException e){
                //future运行占用资源,死锁
                Log.e(TAG, "死锁异常"+e.getMessage());
            }catch (RuntimeIoException e) {
                Log.e(TAG, "连接异常,无法获取session,抓到的异常信息-----"+e.getMessage());
            }catch (Exception e){
                Log.e("状态...", "connect: 连接失败"+e.getMessage());
            }
    }

    /**
     * 检查网络连接的方法
     * @param mContext
     * @return 连接状态返回[true],断开状态返回[false]
     */
    private static boolean CheckNetWork(Context mContext) {
        ConnectivityManager connectivityManager = (ConnectivityManager) mContext
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        if (info == null || !info.isAvailable()) {
            return false;
        } else {
            return true;
        }
    }
    /**
     * 断开连接
     */
    public void disConnect(){
        connector.dispose();
        connector=null;
        address=null;
        Log.e("tag", "断开连接");
    }
}

connector.addListener()这里面用到的

ConnectionThread thread=new ConnectionThread(mContext);
                thread.start();

就是连接线程,我的想法是:开启Mina服务后会调用连接线程,直到连接成功后,自动退出线程,断线后,尝试重新连接,再次调用这个连接线程,直到连接成功后,再次退出这个线程。因为封装的需要,现在把涉及到的类全部复制过来

MinaServer类,开启mina服务

package view.my.ad.minaclientdemo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import view.my.ad.thread.ConnectionThread;

public class MinaService extends Service {
    private static final String TAG = "ZZHMinaService";
    private ConnectionThread thread;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onStartCommand:.........................");
        //启动连接
        thread = new ConnectionThread(this);
        thread.start();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent,flags,startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        thread.DisConnect();
    }
}

ConnectionThread 类,用于连接的线程

package view.my.ad.thread;

import android.content.Context;
import android.util.Log;

import view.my.ad.connector.ConnectionManager;
import view.my.ad.connector.SessionManager;

public class ConnectionThread extends Thread {

    private static final String TAG = "ZZHConnectionThread";
    private ConnectionManager manager;
    private Context mContext;
    private boolean isConnection=false;
    //构造
    public ConnectionThread(Context context) {
        //初始化连接管理者
        mContext=context;
        manager=new ConnectionManager(mContext);
    }
    /***
     * 连接服务器服务器的线程
     * 启动连接(打开应用界面启动,或者开机启动),连接上就关闭线程
     */
    @Override
    public void run() {
        manager.CheckConnect();
        while (true){
            try{
                isConnection = SessionManager.getInstance().CheckSession();
                if (isConnection) {
                    Log.i(TAG, "连接成功,关闭连接线程......");
                    break;
                } else {
                    SessionManager.getInstance().removeSession();
                    Log.e(TAG, "连接失败,尝试重新连接......");
                    Thread.sleep(3000);
                    manager.CheckConnect();
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //断开连接,一般这个线程连接上就主动断开,只有MinaServices被杀掉了才会调用这个断开连接
    public void DisConnect(){
        manager.disConnect();
        interrupt();
    }
}

SessionManager类

package view.my.ad.connector;

import android.util.Log;

import org.apache.mina.core.session.IoSession;

public class SessionManager {
    private static final String TAG = "ZZHSessionManager";
    private static SessionManager mInstance=null;
    private IoSession mSession;
    public static SessionManager getInstance(){
        if(mInstance==null){
            synchronized (SessionManager.class){
                if(mInstance==null){
                    mInstance = new SessionManager();
                }
            }
        }
        return mInstance;
    }

    public void setSession(IoSession session){
        this.mSession = session;
    }

    /**
     * 向服务器发送信息
     * @param msg
     */
    public void writeToServer(Object msg){
        if(mSession!=null && mSession.isConnected()){
            mSession.write(msg);
        }else {
            Log.e(TAG,"没有可用的session,发送未完成......" );
        }
    }

    /**
     * 关闭session
     */
    public void closeSession(){
        if(mSession!=null){
            mSession.closeOnFlush();
        }
    }

    public void removeSession(){
        if (mSession!=null&&mSession.isClosing()){
            mSession=null;
        }
    }

    /**
     * 检查session是否连接
     * @return
     */
    public boolean CheckSession(){
        if (mSession!=null){
            if (mSession.isConnected()){
                return true;
            }else {
                mSession=null;
                return false;
            }
        }else {
            return false;
        }
    }
}

ServerUtil 类,配置服务器的类

package view.my.ad.utils;

public class ServerUtil {
    // 本机服务器测试地址(读者IP请自己配置)
    public final static String SERVER_IP = "192.168.1.107";
    //服务器端口号
    public static final int SERVER_PORT = 5575;
    //设置读缓存大小
    public static final int SERVER_ReadBufferSize=10240;
    //设置超时时间
    public static final long SERVER_ConnectionTimeout=5000;
}

IoListener类

package view.my.ad.utils;

import org.apache.mina.core.service.IoService;
import org.apache.mina.core.service.IoServiceListener;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

public class IoListener implements IoServiceListener {
    @Override
    public void serviceActivated(IoService ioService) throws Exception {

    }

    @Override
    public void serviceIdle(IoService ioService, IdleStatus idleStatus) throws Exception {

    }

    @Override
    public void serviceDeactivated(IoService ioService) throws Exception {

    }

    @Override
    public void sessionCreated(IoSession ioSession) throws Exception {

    }

    @Override
    public void sessionClosed(IoSession ioSession) throws Exception {

    }

    @Override
    public void sessionDestroyed(IoSession ioSession) throws Exception {

    }
}

到此结束,服务器代码基本跟网上的一样,可以去搜一搜

最后附上我的demo,里面也有服务器端的代码((~ ̄▽ ̄)~ 服务器端写的相当简陋!):
http://download.csdn.net/download/mumuliunian/9943226

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值