MINA框架客户端的使用

在网络通信中,有时候需要保持长连接,一般的处理方式是使用socket,但是socket是阻塞式的,并且自己拼写socket的时候,步骤也挺繁杂,很容易出错。因此就想到了使用底层封装socket的框架---MINA框架。MINA框架的客户端是很好处理的,但是服务端网上大多是main函数来实现的。实际项目中,通常有很多需要tomcat来启动,因此就需要整合tomcat和MINA框架。本篇主要介绍MINA框架的获取以及客户端的使用。下一遍主要讲在服务端的使用,以及如何整合到tomcat中。

这个是MINA框架的下载地址 http://mina.apache.org/downloads-mina.html

打开后界面如下:


一个是当前版本的下载,一个是历史版本的下载。点击当前版本下载以后,会跳抓到下一个界面



点击红框处即可下载。当下载完成以后是个zip的压缩包,我们需要的jar包就放在这个压缩包里。网上有很多demo,用到了MINA的三四个jar包。但是,如果只需要满足基本的通信功能,两个jar包就行了。

把压缩包解压出来,会出现三个文件夹,其中dist文件夹里有个mina-core-2.0.16.jar,lib文件夹里有个slf4j-api-1.7.21.jar。这两个jar包就是我们需要的jar。如果是不同的版本,版本号会不一样。即mina-core-版本号.jar和slf4j-api-版本号.jar。我们把这两个jar放入我们的工程就可以开始编码了。

扫描二维码关注公众号,回复: 1085369 查看本文章

下面直接上代码:

==============================================================================

主界面MainActivity很简单,三个按钮,分别是开启服务,关闭服务,和点击发送消息的按钮。这里把与服务器的通信放到了service中进行处理。

package com.testdog.activity;

import android.content.Intent;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import com.dog.minaclient.R;

import com.testdog.manager.SessionManager;

import com.testdog.service.TestService;


public class MainActivity extends BaseActivity {

    @Override

    protected void init() {

        // 在main里面把后台服务开启,然后主动连接服务器

        setContentView(R.layout.activity_main);

        Button btn_start = (Button) findViewById(R.id.btn_start);

        Button btn_end = (Button) findViewById(R.id.btn_end);

        Button btn_send = (Button) findViewById(R.id.btn_send);

        btn_start.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                // TODO Auto-generated method stub

                Intent intent = new Intent(MainActivity.this, TestService.class);

                startService(intent);

            }

        });

        btn_end.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent intent = new Intent(MainActivity.this, TestService.class);

                stopService(intent);

            }

        });

        btn_send.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                SessionManager.getInstance().writeToServer("hello123");

            }

        });

    }

}


===========================================================================

主界面的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="这是主界面"
        />
    
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="启动服务"
        android:id="@+id/btn_start"/>
     <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="关闭服务"
        android:id="@+id/btn_end"/>
     
     <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送数据"
        android:id="@+id/btn_send"/>

</LinearLayout>

===========================================================================

BaseActivity中主要是用于广播事件的注册,接收从服务器发过来的消息进行处理

package com.testdog.activity;

import android.app.Activity;

import android.content.IntentFilter;

import android.os.Bundle;

import android.support.v4.content.LocalBroadcastManager;

import com.testdog.broadcast.MessageBroadcastReceiver;

public abstract class BaseActivity extends Activity {

    private MessageBroadcastReceiver receiver; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        registerBroadcast();

        init();

    }

    protected abstract void init();
    
    private void registerBroadcast() {

        receiver = new MessageBroadcastReceiver();

        IntentFilter filter = new IntentFilter();

        filter.addAction("com.commonlibrary.mina.broadcast");

        LocalBroadcastManager.getInstance(this).registerReceiver(receiver,filter);

    }

    private void unregisterBroadcast(){ 

        LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver); 

    }  
 
    @Override  
    protected void onDestroy() { 

        super.onDestroy(); 

        unregisterBroadcast(); 

    } 
}


===========================================================================

广播接收者类:

package com.testdog.broadcast;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.widget.Toast;

public class MessageBroadcastReceiver extends BroadcastReceiver{ 

    @Override  
    public void onReceive(Context context, Intent intent) { 

        // 接受到广播以后进行判断,更具操作进行相应的跳转    

        String a = (String) intent.getExtras().get("message");

        Toast.makeText(context, a, 0).show();

    } 


====================================================================

服务器的访问ip配置类

package com.testdog.config;

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; 

        } 

    } 



==========================================================================

链接服务器的管理类,主要是对MINA框架的一些配置,以及编解码规则。

package com.testdog.manager;

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.prefixedstring.PrefixedStringCodecFactory;

import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;

import org.apache.mina.filter.codec.textline.LineDelimiter;

import org.apache.mina.filter.codec.textline.TextLineCodecFactory;

import org.apache.mina.filter.logging.LoggingFilter;

import org.apache.mina.transport.socket.nio.NioSocketConnector;

import com.testdog.config.ConnectionConfig;

import java.lang.ref.WeakReference;

import java.net.InetSocketAddress;

import java.nio.charset.Charset;

/**
 * Description:
 */
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());

        try {

            mConnection = new NioSocketConnector();

            mConnection.getSessionConfig().setReadBufferSize(mConfig.getReadBufferSize());

            mConnection.getFilterChain().addLast("logging", new LoggingFilter());

            mConnection.getFilterChain().addLast("codec",new ProtocolCodecFilter(new TextLineCodecFactory(Charset

                    .forName("UTF-8"), LineDelimiter.WINDOWS.getValue(),

                    LineDelimiter.WINDOWS.getValue())));

            mConnection.setHandler(new DefaultHandler(mContext.get()));

            mConnection.setDefaultRemoteAddress(mAddress);

        } catch (Exception e) {

            e.printStackTrace();

        }
    }

    /**
     * 与服务器连接
     *
     * @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 = null;

                // 在这里进行判断服务器发过来的消息类别

                if("出库".equals("出库")){

                    intent = new Intent(BROADCAST_ACTION);           

                } else if("入库".equals("")){

                    intent = new Intent(BROADCAST_ACTION);

                } else {

                    //......

                }

                intent.putExtra(MESSAGE, message.toString());

                LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);

            }

        }

    }

}


messageReceived方法用来接收服务器发来的消息,然后把消息通过广播发送出去并做相应的处理。我这里是出库入库事件,而实际应用过程中,具体逻辑需要根据具体的需求去写。


==============================================================================


session管理器。session对象是客户端和服务器端进行通信的基础。通过session对象可以写入或者写出数据。每一个客户端链接服务器都会生成一个session对象。如果多个客户端同时连接服务器,可以使用Map集合把session对象存起来。

package com.testdog.manager;

import android.util.Log;

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

/**
 * Description: User: chenzheng Date: 2016/12/9 0009 Time: 17:50
 */
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(String msg) {

        if (mSession != null) {

            Log.e("tag", "客户端准备发送消息");

            mSession.write(msg);

        }

    }

    public void closeSession() {

        if (mSession != null) {

            mSession.closeOnFlush();

        }

    }

    public void removeSession() {

        this.mSession = null;

    }

}

===================================================================================

后台服务类代码

package com.testdog.service;

import com.testdog.thread.MyThread;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

/**
 * 后台运行的服务,用来处理一些后台逻辑,比如接收到来自服务器端的请求以后,进行一些界面上的处理
 *
 * @author Administrator
 *
 */
public class TestService extends Service {

    private MyThread myThread;
    
    @Override
    public IBinder onBind(Intent intent) {

        return null;

    }

    @Override
    public void onCreate() {

        super.onCreate();

        // 在onCreate方法里连接服务器

        myThread = new MyThread("mina", getApplicationContext());

        // 启动线程

        myThread.start();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        return super.onStartCommand(intent, flags, startId);

    }

    @Override
    public void onDestroy() {

        // TODO Auto-generated method stub

        super.onDestroy();

        myThread.disConnect();

        // 把进程杀死

        myThread.interrupt();

    }

}

===================================================================

后台运行的线程自定义线程

package com.testdog.thread;

import com.testdog.config.ConnectionConfig;

import com.testdog.manager.ConnectionManager;

import android.content.Context;

import android.os.HandlerThread;

import android.util.Log;

public class MyThread extends HandlerThread {

    private Context mContext;

    boolean isConnection;

    ConnectionManager mManager;

    public MyThread(String name, Context context) {

        super(name);

        mContext = context;

        // 主动连接服务器

        // 连接服务器的配置类
        ConnectionConfig config = new ConnectionConfig.Builder(context)

                .setIp("192.168.1.190").setPort(10086).setReadBufferSize(2048)

                .setConnectionTimeout(10000).builder();

        // 连接服务器的管理类

        mManager = new ConnectionManager(config);

    }

    /**
     * loop循环,用来处理与服务器的连接
     */
    @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();

     } 

}


=======================================================================================

清单文件中添加的权限

    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <uses-permission android:name="android.permission.BLUETOOTH" />

    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <uses-permission android:name="android.permission.INTERNET" />

清单文件中添加服务

 <service android:name="com.testdog.service.TestService" ></service>


好了,这就是demo全部代码,只要全部粘贴过去就能使用了,以上亲测可用。服务端整合tomcat由于篇幅太长了,将在下篇中贴出来。

猜你喜欢

转载自blog.csdn.net/little_soybean/article/details/79056287