Android之Mina框架学习

  1. 什么是Mina?
    Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序(只在最新的预览版中提供),MINA 所支持的功能也在进一步的扩展中。
    总之:我们简单理解它是一个封装底层IO操作,提供高级操作API的通讯框架
     
  2. 什么是NIO技术?

    在JDK1.4以前,I/O输入输出处理,我们把它称为旧I/O处理,在JDK1.4开始,java提供了一系列改进的输入/输出新特性,这些功能被称为新I/O(NEW I/O),新添了许多用于处理输入/输出的类,这些类都被放在java.nio包及子包下,并且对原java.io包中的很多类以NIO为基础进行了改写,新添了满足新I/O的功能。

    Java NIO和IO的主要区别

    面向缓冲(Buffer)

    在整个Java的心I/O中,所以操作都是以缓冲区进行的,使操作的性能大大提高。更多请参考这里这里

  3. 什么是长连接、短连接、心跳包?请参考这里

  4. 常见的Java NIO框架有哪些?
    Mina、Netty、Grizzly、xSocket等,区别如下:
     

    Mina

    Mina(Multipurpose Infrastructure for Network Applications) 是 Apache组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 Mina 版本2.04支持基于 JavaNIO 技术的 TCP/UDP 应用程序开发、串口通讯程序,Mina 所支持的功能也在进一步的扩展中。目前,正在使用Mina的应用包括:Apache Directory Project、AsyncWeb、AMQP(Advanced MessageQueuing Protocol)、RED5 Server(Macromedia? FlashMedia RTMP)、ObjectRADIUS、 Openfire等等。

    Netty

    Netty是一款异步的事件驱动的网络应用框架和工具,用于快速开发可维护的高性能、高扩展性协议服务器和客户端。也就是说,Netty是一个NIO客户端/服务器框架,支持快速、简单地开发网络应用,如协议服务器和客户端。它极大简化了网络编程,如TCP和UDP套接字服务器。

    Grizzly

    Grizzly是一种应用程序框架,专门解决编写成千上万用户访问服务器时候产生的各种问题。使用JAVANIO作为基础,并隐藏其编程的复杂性。容易使用的高性能的API。带来非阻塞socketd到协议处理层。利用高性能的缓冲和缓冲管理使用高性能的线程池。

    xSocket

    xSocket:是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。(只是对Java的NIO做了最简单的封装,以便于开发使用。)

    OK,我们现在可以看看三者的简单对比了。

    首先,从设计的理念上来看,Mina的设计理念是最为优雅的。当然,由于Netty的主导作者与Mina的主导作者是同一人,出自同一人之手的Netty在设计理念上与Mina基本上是一致的。而Grizzly在设计理念上就较差了点,几乎是JavaNIO的简单封装。

    其次,从项目的出身来看,Mina出身于开源界的大牛Apache组织,Netty出身于商业开源大亨Jboss,而Grizzly则出身于土鳖Sun公司。从其出身可以看到其应用的广泛程序,到目前为止,我见到业界还是使用Mina多一些,而Netty也在慢慢的应用起来,而Grizzly则似乎只有Sun自已的项目使用了,如果还有其他的公司或开源项目在使用,那就算我孤陋寡闻。 最后,从入门的文档来说,由于Mina见世时间相对较长,官方以及民间的文档与入门示例都相当的多。Netty的官方文档也做得很好,而民间文档就要相对于Mina少一些了。至于Grizzly,不管是官方还是民间,都很少见到其文档。

  5. 常见的Mina使用场景有哪些?
    如:客户端和服务端进行socket通讯时,服务端需要知道客户端的是否在线,这就要求客户端要一直定时发送心跳请求告知服务端;通讯服务中断后,客户端自动发起重新连接等等。。。有同学说:这功能几个普通函数就能实现,没啥特别的啊?开始我也是这样想的,但慢慢了解Mina框架后,发现很多底层操作都封装好了,简单易用,真的比自己砌砖爽多了……自己实现请参考
  6. Mina如何实现通讯?
    下面以Mina实现Android客户端与服务器端通信为例,原文参考

    二、服务器端代码

    MinaService.java
    
    package com.czhappy.mina;
     
    import java.net.InetSocketAddress;
    import java.util.Date;
     
    import org.apache.mina.core.service.IoAcceptor;
    import org.apache.mina.core.service.IoHandlerAdapter;
    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.serialization.ObjectSerializationCodecFactory;
    import org.apache.mina.filter.logging.LoggingFilter;
    import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
     
    public class MinaService {
     
        public static void main(String[] args) {
            IoAcceptor acceptor = new NioSocketAcceptor();
            //添加日志过滤器
            acceptor.getFilterChain().addLast("logger", new LoggingFilter());
            acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
            acceptor.setHandler(new DemoServerHandler());
            acceptor.getSessionConfig().setReadBufferSize(2048);
            acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
            try {
                acceptor.bind(new InetSocketAddress(9226));
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("启动服务");
        }
        
        /**  
         * @ClassName: DemoServerHandler  
         * @Description: 负责session对象的创建和监听以及消息的创建和接收监听
         * @author chenzheng
         * @date 2016-12-9 下午3:57:11  
         */
        private static class DemoServerHandler extends IoHandlerAdapter{
            
            //服务器与客户端创建连接
            @Override
            public void sessionCreated(IoSession session) throws Exception {
                System.out.println("服务器与客户端创建连接...");
                super.sessionCreated(session);
            }
     
            
            @Override
            public void sessionOpened(IoSession session) throws Exception {
                System.out.println("服务器与客户端连接打开...");
                super.sessionOpened(session);
            }
            
            //消息的接收处理
            @Override
            public void messageReceived(IoSession session, Object message)
                    throws Exception {
                // TODO Auto-generated method stub
                super.messageReceived(session, message);
                String str = message.toString();
                Date date = new Date();
                session.write(date.toString());
                System.out.println("接收到的数据:"+str);
                
            }
            
            @Override
            public void messageSent(IoSession session, Object message)
                    throws Exception {
                // TODO Auto-generated method stub
                super.messageSent(session, message);
            }
            
            @Override
            public void sessionClosed(IoSession session) throws Exception {
                // TODO Auto-generated method stub
                super.sessionClosed(session);
            }
        }
    }

    三、Android客户端代码
     

    ConnectionConfig.java
    
    
    package com.czhappy.minaclient;
     
    import android.content.Context;
     
    /**
     * Description:构建者模式
     */
    public class ConnectionConfig {
     
        private Context context;
        private String ip;
        private int port;
        private int readBufferSize;
        private long connectionTimeout;
     
        public Context getContext() {
            return context;
        }
     
        public String getIp() {
            return ip;
        }
     
        public int getPort() {
            return port;
        }
     
        public int getReadBufferSize() {
            return readBufferSize;
        }
     
        public long getConnectionTimeout() {
            return connectionTimeout;
        }
     
        public static class Builder{
            private Context context;
            private String ip = "192.168.168.20";
            private int port = 9226;
            private int readBufferSize = 10240;
            private long connectionTimeout = 10000;
     
            public Builder(Context context){
                this.context = context;
            }
     
            public Builder setIp(String ip){
                this.ip = ip;
                return this;
            }
     
            public Builder setPort(int port){
                this.port = port;
                return this;
            }
     
            public Builder setReadBufferSize(int readBufferSize){
                this.readBufferSize = readBufferSize;
                return this;
            }
     
            public Builder setConnectionTimeout(long connectionTimeout){
                this.connectionTimeout = connectionTimeout;
                return this;
            }
     
            private void applyConfig(ConnectionConfig config){
     
                config.context = this.context;
                config.ip = this.ip;
                config.port = this.port;
                config.readBufferSize = this.readBufferSize;
                config.connectionTimeout = this.connectionTimeout;
            }
     
            public ConnectionConfig builder(){
                ConnectionConfig config = new ConnectionConfig();
                applyConfig(config);
                return config;
            }
        }
    }
    
    ConnectionManager.java
    
    package com.czhappy.minaclient;
     
    import android.content.Context;
    import android.content.Intent;
    import android.support.v4.content.LocalBroadcastManager;
    import android.util.Log;
     
    import org.apache.mina.core.future.ConnectFuture;
    import org.apache.mina.core.service.IoHandlerAdapter;
    import org.apache.mina.core.session.IoSession;
    import org.apache.mina.filter.codec.ProtocolCodecFilter;
    import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
    import org.apache.mina.filter.logging.LoggingFilter;
    import org.apache.mina.transport.socket.nio.NioSocketConnector;
     
    import java.lang.ref.WeakReference;
    import java.net.InetSocketAddress;
     
    public class ConnectionManager {
     
        private static final String BROADCAST_ACTION = "com.commonlibrary.mina.broadcast";
        private static final String MESSAGE = "message";
        private ConnectionConfig mConfig;
        private WeakReference<Context> mContext;
     
        private NioSocketConnector mConnection;
        private IoSession mSession;
        private InetSocketAddress mAddress;
     
        public ConnectionManager(ConnectionConfig config){
     
            this.mConfig = config;
            this.mContext = new WeakReference<Context>(config.getContext());
            init();
        }
     
        private void init() {
            mAddress = new InetSocketAddress(mConfig.getIp(), mConfig.getPort());
            mConnection = new NioSocketConnector();
            mConnection.getSessionConfig().setReadBufferSize(mConfig.getReadBufferSize());
            mConnection.getFilterChain().addLast("logging", new LoggingFilter());
            mConnection.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
            mConnection.setHandler(new DefaultHandler(mContext.get()));
            mConnection.setDefaultRemoteAddress(mAddress);
        }
     
        /**
         * 与服务器连接
         * @return
         */
        public boolean connnect(){
            Log.e("tag", "准备连接");
            try{
                ConnectFuture future = mConnection.connect();
                future.awaitUninterruptibly();
                mSession = future.getSession();
     
                SessionManager.getInstance().setSeesion(mSession);
     
            }catch (Exception e){
                e.printStackTrace();
                Log.e("tag", "连接失败");
                return false;
            }
     
            return mSession == null ? false : true;
        }
     
        /**
         * 断开连接
         */
        public void disContect(){
            mConnection.dispose();
            mConnection=null;
            mSession=null;
            mAddress=null;
            mContext = null;
            Log.e("tag", "断开连接");
        }
     
        private static class DefaultHandler extends IoHandlerAdapter{
     
            private Context mContext;
            private DefaultHandler(Context context){
                this.mContext = context;
     
            }
     
            @Override
            public void sessionOpened(IoSession session) throws Exception {
                super.sessionOpened(session);
            }
     
            @Override
            public void messageReceived(IoSession session, Object message) throws Exception {
                Log.e("tag", "接收到服务器端消息:"+message.toString());
                if(mContext!=null){
                    Intent intent = new Intent(BROADCAST_ACTION);
                    intent.putExtra(MESSAGE, message.toString());
                    LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
                }
            }
        }
    }
    
    
    
    
    
    MinaService.java
    
    package com.czhappy.minaclient;
     
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.os.HandlerThread;
    import android.os.IBinder;
    import android.support.annotation.Nullable;
    import android.util.Log;
    
    public class MinaService extends Service{
     
        private ConnectionThread thread;
     
     
        @Override
        public void onCreate() {
            super.onCreate();
            thread = new ConnectionThread("mina", getApplicationContext());
            thread.start();
            Log.e("tag", "启动线程尝试连接");
        }
     
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            return super.onStartCommand(intent, flags, startId);
        }
     
        @Override
        public void onDestroy() {
            super.onDestroy();
            thread.disConnect();
            thread=null;
     
        }
     
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
     
        class ConnectionThread extends HandlerThread{
     
            private Context context;
            boolean isConnection;
            ConnectionManager mManager;
            public ConnectionThread(String name, Context context){
                super(name);
                this.context = context;
     
                ConnectionConfig config = new ConnectionConfig.Builder(context)
                        .setIp("192.168.168.20")
                        .setPort(9226)
                        .setReadBufferSize(10240)
                        .setConnectionTimeout(10000).builder();
     
                mManager = new ConnectionManager(config);
            }
     
            @Override
            protected void onLooperPrepared() {
                while(true){
                    isConnection = mManager.connnect();
                    if(isConnection){
                        Log.e("tag", "连接成功");
                        break;
                    }
                    try {
                        Log.e("tag", "尝试重新连接");
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
     
            public void disConnect(){
                mManager.disContect();
            }
        }
    }
    
    
    
    
    
    SessionManager.java
    
    package com.czhappy.minaclient;
    import android.util.Log;
    import org.apache.mina.core.session.IoSession;
     
    public class SessionManager {
     
        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;
        }
     
        private SessionManager(){}
     
        public void setSeesion(IoSession session){
            this.mSession = session;
        }
     
        public void writeToServer(Object msg){
            if(mSession!=null){
                Log.e("tag", "客户端准备发送消息");
                mSession.write(msg);
            }
        }
     
        public void closeSession(){
            if(mSession!=null){
                mSession.closeOnFlush();
            }
        }
     
        public void removeSession(){
            this.mSession=null;
        }
    }
    
    
    
    
    
    
    
    MinaTestActivity.java
    
    package com.czhappy.minaclient;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.Bundle;
    import android.support.v4.content.LocalBroadcastManager;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.TextView;
    
    public class MinaTestActivity extends AppCompatActivity implements View.OnClickListener{
     
        private TextView start_service_tv, send_tv, receive_tv;
     
        private MessageBroadcastReceiver receiver;
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_mina_test);
     
            initView();
            registerBroadcast();
     
        }
     
        private void registerBroadcast() {
            receiver = new MessageBroadcastReceiver();
            IntentFilter filter = new IntentFilter("com.commonlibrary.mina.broadcast");
            LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
        }
     
        private void initView() {
            receive_tv = (TextView) this.findViewById(R.id.receive_tv);
            start_service_tv = (TextView) this.findViewById(R.id.start_service_tv);
            start_service_tv.setOnClickListener(this);
            send_tv = (TextView) this.findViewById(R.id.send_tv);
            send_tv.setOnClickListener(this);
     
        }
     
        @Override
        public void onClick(View v) {
            switch(v.getId()){
                case R.id.start_service_tv:
                    Log.e("tag", "点击启动服务");
                    Intent intent = new Intent(this, MinaService.class);
                    startService(intent);
                    break;
                case R.id.send_tv:
                    Log.e("tag", "点击发送消息");
                    SessionManager.getInstance().writeToServer("hello123");
                    break;
            }
        }
     
        private void unregisterBroadcast(){
            LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
        }
     
        @Override
        protected void onDestroy() {
            super.onDestroy();
            stopService(new Intent(this, MinaService.class));
            unregisterBroadcast();
     
        }
     
        private class MessageBroadcastReceiver extends BroadcastReceiver{
            @Override
            public void onReceive(Context context, Intent intent) {
     
                receive_tv.setText(intent.getStringExtra("message"));
            }
        }
    }

    四、运行结果
    1.点击启动服务,观察客户端是否与服务器端连接成功;
    2.点击发送消息,观察消息是否发送成功,如果失败判断失败在哪一步。客户端运行结果:


    服务器端运行结果:

    源码下载:http://download.csdn.net/detail/chenzheng8975/9707406

  7. 我使用Mina遇到的坑
    1)客户端无法得到服务器的返回值
    解决方案:一定要正确设置编码、解码器,千万不要直接搬别人的代码。


    StringDecoder和StringEncoder报文内容格式,请与服务端约定好。


    2)客户端频繁发送心跳包,解决方法:参考这里

     
  8. 利用Mina实现聊天室,可以参考这里
  9. 其他参考

 

 

 

  1.  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值