Android mina长连接 (二)

文章出处:https://blog.csdn.net/chenzheng8975/article/details/53558387

本篇文章和出处一样 只是加了一些注释 

1.mina服务器搭建

搭建思路 --调用mina为我们提供的服务器API即可完成


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

2.mina客户端工程创建

需要jar包   mina-core-2.0.16.jar   和  slf4j-android-1.6.1-RC1.jar

创建一个Service,用来与远程服务器连接

封装一个ConnectionManager类用来提供与服务器连接的方法,ConnectionManager写成一个单利的 双加锁

在Service中启动线程,调用ConnectionManager完成连接的创建,Service中的IOSession 消息接受的到后用局部广播发送出去

ConnectionConfig.java 使用构建者模式


package com.czhappy.minaclient;
 
import android.content.Context;
 
/**
 * Description:构建者模式
 * User: chenzheng
 * Date: 2016/12/9 0009
 * Time: 16:37
 */
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;
    }
    
    //--------在构建者模式中 以上代码是 先写的 默认-------------------
    // 通过Builder内部类  
    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;//10秒
 
        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;
 
/**
 * Description:
 * User: chenzheng
 * Date: 2016/12/9 0009
 * Time: 16:21
 */
public class ConnectionManager {
     //广播的acton 一般使用包名 命名
    private static final String BROADCAST_ACTION = "com.commonlibrary.mina.broadcast";
    private static final String MESSAGE = "message";
    private ConnectionConfig mConfig;//要配置一些参数 ip 端口,在这里使用构建者模式,动态的设置
    private WeakReference<Context> mContext;//为了确保防止内存溢出,使用弱引用 对context一层包装
    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 disContection(){
        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 {
            //将我们的session保存到我们的session manager类中,从而可以发送消息到服务器
        }
 
        @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);//开始想使用第三方的框架relsbus将消息抛出去,后来感觉太依赖这个框架,这样不太好,最后就Android自带的广播机制将消息发送出去,使用局部广播 将收到的消息 发出去,其他app监听不到 比较安全
            }
        }
    }
}

MinaService.java   使用Service 调用ConnectionManager来完成与服务器之间的连接

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;
 
/**
 * Description:
 * User: chenzheng
 * Date: 2016/12/9 0009
 * Time: 17:17
 */
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;
    }
     /**
       * 负责调用connection manager类来完成与服务器的连接
       * 这也可以用普通的Thread  这里演示了HandlerThread的使用
       */
    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);
        }
        
        /**
          * 开始连接我们的服务器
          * 这个方法相当于普通线程中的run()方法
          */
        @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 disConnection(){
            mManager.disContection();//完成与服务器的断开操作
        }
    }
}

SessionManager.java

package com.czhappy.minaclient;
 
import android.util.Log;
 
import org.apache.mina.core.session.IoSession;
 
/**
 * Description: Session管理的单利对象,双加锁机制
 * 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(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;
 
/**
 * Description:
 * User: chenzheng
 * Date: 2016/12/9 0009
 * Time: 18:01
 */
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"));
        }
    }
}

3.运行结果

1.点击启动服务,观察客户端是否与服务器端连接成功;

2.点击发送消息,观察消息是否发送成功,如果失败判断失败在哪一步。

客户端运行结果:

服务器端运行结果:

4.源码下载

http://download.csdn.net/detail/chenzheng8975/9707406

50积分下载   

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值