Android mina框架使用详情

Mina框架jar包的导入

登录http://mina.apache.org/downloads.html下载最新 mina压缩包(我下的是apache-mina-2.0.13-bin.zip),解压获得mina-core-2.0.13.jar和slf4j-api-1.7.14.jar(注:slf4j-api-1.7.14.jar文件在apache-mina-2.0.13-bin.zip\apache-mina-2.0.13\lib目录下)

Mina请求的基本配置

public class ConnectionManager {

    private static final String TAG = "MinaClientDemo";
    //创建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, 100);
        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.getFilterChain().addLast("mycoder", new ProtocolCodecFilter(new MyCodecFactory()));
        //设置超时
        connector.setConnectTimeoutCheckInterval(ServerUtil.SERVER_ConnectionTimeout);
        connector.setHandler(new DefaultHandler(mContext));
        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", "断开连接");
    }


    private class DefaultHandler extends IoHandlerAdapter {

        private Context mContext;

        private DefaultHandler(Context context) {
            this.mContext = context;
        }

        @Override
        public void sessionCreated(IoSession session) throws Exception {
            super.sessionCreated(session);
            SessionManager.getInstance().setSession(session);
            Log.i(TAG, "sessionCreated");
        }

        @Override
        public void sessionOpened(IoSession session) throws Exception {
            super.sessionOpened(session);
            Log.d(TAG, "连接打开===> ID ====>" + session.getId());

        }

        @Override
        public void sessionClosed(IoSession session) throws Exception {
            super.sessionClosed(session);
            Log.e(TAG, "sessionClosed");
            SessionManager.getInstance().closeSession();
            SessionManager.getInstance().removeSession();
        }

        @Override
        public void messageReceived(IoSession session, Object message) throws Exception {
            Log.d(TAG, "收到数据,接下来你要怎么解析数据就是你的事了");
            IoBuffer buf = (IoBuffer) message;
            HandlerEvent.getInstance().handle(buf);
        }

        @Override
        public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
            super.sessionIdle(session, status);
            Log.e(TAG, "sessionIdle");
            SessionManager.getInstance().closeSession();
        }

        @Override
        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
            super.exceptionCaught(session, cause);
            Log.e(TAG, "--------------连接发生异常------------" + cause.toString());
            SessionManager.getInstance().closeSession();
        }
    }


}

长连接的Service

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

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

    }

    @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();
    }


    /**
     * 以固定周期频率执行任务
     */
    public void executeFixedRate() {
        if (executor != null) {
            executor.shutdown();
            executor = null;
        }
        executor = Executors.newScheduledThreadPool(1);
        executor.scheduleAtFixedRate(
                new EchoServer(),
                0,
                1000 * 3,
                TimeUnit.MILLISECONDS);
    }

    class EchoServer implements Runnable {
        @Override
        public void run() {
            sendMsg("001////0124646846");
        }
    }


    /**
     * 给服务器发送一条消息
     */
    public void sendMsg(String msg) {
        /**
         * 假定消息格式为:消息头(一个short类型:表示事件号、一个int类型:表示消息体的长度)+消息体
         */
        MinaMsgHead msgHead = new MinaMsgHead();
        msgHead.bodyLen = msg.length();
        IoBuffer buffer = IoBuffer.allocate(4 + msgHead.bodyLen);
        buffer.putInt(msgHead.bodyLen);
        try {
            byte[] b = msg.getBytes("gbk");
            String sa = new String(b, "gbk");
            b = sa.getBytes("utf-8");
            buffer.put(b);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        if (SessionManager.getInstance().CheckSession()){
            //发送
            Log.e("TAG","发送成功!");
            SessionManager.getInstance().writeToServer(buffer);
        }else {
            Log.e("TAG","发送失败!");
        }


    }
    
}

长连接的线程

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

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

    }

    @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();
    }


    /**
     * 以固定周期频率执行任务
     */
    public void executeFixedRate() {
        if (executor != null) {
            executor.shutdown();
            executor = null;
        }
        executor = Executors.newScheduledThreadPool(1);
        executor.scheduleAtFixedRate(
                new EchoServer(),
                0,
                1000 * 3,
                TimeUnit.MILLISECONDS);
    }

    class EchoServer implements Runnable {
        @Override
        public void run() {
            sendMsg("001////0124646846");
        }
    }


    /**
     * 给服务器发送一条消息
     */
    public void sendMsg(String msg) {
        /**
         * 假定消息格式为:消息头(一个short类型:表示事件号、一个int类型:表示消息体的长度)+消息体
         */
        MinaMsgHead msgHead = new MinaMsgHead();
        msgHead.bodyLen = msg.length();
        IoBuffer buffer = IoBuffer.allocate(4 + msgHead.bodyLen);
        buffer.putInt(msgHead.bodyLen);
        try {
            byte[] b = msg.getBytes("gbk");
            String sa = new String(b, "gbk");
            b = sa.getBytes("utf-8");
            buffer.put(b);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        if (SessionManager.getInstance().CheckSession()){
            //发送
            Log.e("TAG","发送成功!");
            SessionManager.getInstance().writeToServer(buffer);
        }else {
            Log.e("TAG","发送失败!");
        }


    }
    
}

添加解码器

public class MyCodecFactory implements ProtocolCodecFactory {
    private MyDataDecoder decoder;
    private MyDataEncoder encoder;
    public MyCodecFactory() {
        encoder = new MyDataEncoder();
        decoder = new MyDataDecoder();
    }
    @Override
    public ProtocolDecoder getDecoder(IoSession session) throws Exception {
        return decoder;
    }
    @Override
    public ProtocolEncoder getEncoder(IoSession session) throws Exception {
        return encoder;
    }
}
public class MyDataDecoder extends CumulativeProtocolDecoder {
    /**
     * 返回值含义:
     * 1、当内容刚好时,返回false,告知父类接收下一批内容
     * 2、内容不够时需要下一批发过来的内容,此时返回false,这样父类 CumulativeProtocolDecoder
     * 会将内容放进IoSession中,等下次来数据后就自动拼装再交给本类的doDecode
     * 3、当内容多时,返回true,因为需要再将本批数据进行读取,父类会将剩余的数据再次推送本类的doDecode方法
     */
    @Override
    public boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
            throws Exception {
        /**
         * 假定消息格式为:消息头(int类型:表示消息体的长度、short类型:表示事件号)+消息体
         */
        if (in.remaining() < 4)//是用来当拆包时候剩余长度小于4的时候的保护,不加容易出错
        {
            return false;
        }
        if (in.remaining() > 1) {
            //以便后继的reset操作能恢复position位置
            in.mark();
            ////前6字节是包头,一个int和一个short,我们先取一个int
            int len = in.getInt();//先获取包体数据长度值

            //比较消息长度和实际收到的长度是否相等,这里-2是因为我们的消息头有个short值还没取
//            if (len > in.remaining() - 2) {
            if (len > in.remaining() ) {
                //出现断包,则重置恢复position位置到操作前,进入下一轮, 接收新数据,以拼凑成完整数据
                in.reset();
                return false;
            } else {
                //消息内容足够
                in.reset();//重置恢复position位置到操作前
//                int sumLen = 6 + len;//总长 = 包头+包体
                int sumLen = 4 + len;//总长 = 包头+包体
                byte[] packArr = new byte[sumLen];
                in.get(packArr, 0, sumLen);
                IoBuffer buffer = IoBuffer.allocate(sumLen);
                buffer.put(packArr);
                buffer.flip();
                out.write(buffer);
                //走到这里会调用DefaultHandler的messageReceived方法

                if (in.remaining() > 0) {//出现粘包,就让父类再调用一次,进行下一次解析
                    return true;
                }
            }
        }
        return false;//处理成功,让父类进行接收下个包
    }
}
/**
 *  编码器将数据直接发出去(不做处理)
 */
public class MyDataEncoder extends ProtocolEncoderAdapter {

    @Override
    public void encode(IoSession session, Object message,
                       ProtocolEncoderOutput out) throws Exception {
        IoBuffer value = (IoBuffer) message;
        out.write(value);
        out.flush();

    }
}

需要注意的地方

1.能收到服务器发送过来的数据,但是显示如下样式,无法进行到自己定义的数据解析

D/o.a.m.f.c.Protoco: Processing a MESSAGE_RECEIVED for session 2

这种情况一般是因为自己配置的解码器没有正确的解码出来服务器推送的数据导致的。请参考上文添加解码器部分,在Mina基本配置里面配置好相应的解码器。

2.能连上服务器,但是发送的消息无法成功发送
这个需要和后台定义好通讯协议,在demo中我是用的是IoBuffer,两边定义好事件号和消息体,并且需要在解码器中配置好对应的解码的消息类型。demo中我并没有使用事件号,而是直接将标示位和数据位一起放在了消息体中。

3.后台无法解析发送上去的数据
请检查前后端定义的消息是否一致(事件号+消息体),定义的长度是否一致。

最后附上demo地址:https://download.csdn.net/download/d38825/10303736

你可能感兴趣的:(Android mina框架使用详情)