android使用Mina实现与服务器长连接

1.下载包:

Mina下载页:http://mina.apache.org/downloads-mina.html
快速下载链接:http://mirrors.cnnic.cn/apache/mina/mina/2.0.16/apache-mina-2.0.16-bin.tar.gz
将下载好的包解压出来,将dist/mina-core-2.0.16.jar和lib/slf4j-api-1.7.21.jar拷贝到工程目录中,进入Project Structure->Dependencies将这两个jar包添加为新的File Dependency。

java api doc:http://mina.apache.org/mina-project/apidocs/index.html

2.配置相关参数

长连接

    private static Boolean Closed = false;
    private static NioSocketConnector connector;
    private static IoSession session;

   private void init() {
        connector = new NioSocketConnector();
        connector.setConnectTimeoutMillis(CONNECT_TIMEOUT);
        //配置日志
        connector.getFilterChain().addLast("logger", new LoggingFilter());
        //配置解码器与编码器
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new AppProtocolCodecFactory()));
        //配置数据返回处理
        connector.setHandler(new AppSocketIoHandler());
        //设置接收缓存区大小
        connector.getSessionConfig().setReceiveBufferSize(65536);//读取缓冲去大小最大65536,64KB
        connector.getSessionConfig().setMinReadBufferSize(1024*64);//读取缓冲去大小最大65536,64KB
        //设置心跳工程
        KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();
         当读操作空闲时发送心跳
        KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory);
        // 设置心跳包请求后超时无反馈情况下的处理机制,默认为关闭连接,在此处设置为输出日志提醒
        heartBeat.setRequestTimeoutHandler(KeepAliveRequestTimeoutHandler.LOG);
        /** 是否回发 */
        heartBeat.setForwardEvent(false);
        /** 发送频率 */
        heartBeat.setRequestInterval(60);// 单位应该是秒
        /** 设置心跳包请求后 等待反馈超时时间。 超过该时间后则调用KeepAliveRequestTimeoutHandler.CLOSE */
        heartBeat.setRequestTimeout(15);//  单位应该是秒
        connector.getSessionConfig().setKeepAlive(true);
        connector.getFilterChain().addLast("heartbeat", heartBeat);

    }

连接服务器:

 private void Connect() {
        while (!Closed) {
            try {
                ConnectFuture future = connector.connect(new InetSocketAddress(SERVER_ADDRESS, SERVER_POST));
                future.awaitUninterruptibly();
                session = future.getSession();
                System.out.println("TCP 客户端启动");
                break;
            } catch (RuntimeIoException e) {
                e.printStackTrace();
                try {
                    this.sleep(5000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        }


    }

关闭连接:

  public void Close() {
        Closed = true;
        if (connector != null) {
            connector.dispose(true);
            connector = null;
        }

    }

发送数据:

 public void Write(Object bs) {
        if (session != null) {
            session.write(bs);
        }

    }

3.一些说明

配置解码器与编码器

  connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new AppProtocolCodecFactory()));

为什么要配置这个,因为一般写出与读入时都是字节数组,而我们一般操作的是我们自己定义的对象,所以可以通过自定义这个ProtocolCodecFactory去进行转换。


public class AppProtocolCodecFactory implements ProtocolCodecFactory {
    private String tag = "AppProtocolCodecFactory";

    @Override
    public ProtocolEncoder getEncoder(IoSession ioSession) throws Exception {
        //编码器,可以通过它将写入的对象转为写入的数组
        return new AppProtocolEncoder();
    }

    @Override
    public ProtocolDecoder getDecoder(IoSession ioSession) throws Exception {
        //解码器,通过它将读入的数组转为我们想看到的对象
        return new AppProtocolDecoder();
    }


    public class AppProtocolEncoder extends ProtocolEncoderAdapter {
        @Override
        public void encode(IoSession ioSession, Object o, ProtocolEncoderOutput protocolEncoderOutput) throws Exception {
        //这个Object是发送数据时传入的那个Object,就是我们使用的对象
            我们的对象 m = (我们的对象) o;
            Logger.e(tag, "encode");
            if (o == null) {
                Logger.e(tag, "AppSocketMessage is null");
            } else {
                IoBuffer buffer = IoBuffer.allocate(20);
                // 自动扩容
                buffer.setAutoExpand(true);
                // 自动收缩
                buffer.setAutoShrink(true);
                buffer.put(getSocketSendData(m));//把对象转为数组类型
                buffer.flip();
                protocolEncoderOutput.write(buffer);

            }
        }
    }



    public class AppProtocolDecoder extends ProtocolDecoderAdapter {
        @Override
        public void decode(IoSession ioSession, IoBuffer ioBuffer, ProtocolDecoderOutput protocolDecoderOutput) throws Exception {
            Logger.e(tag, "decode");
            int limit = ioBuffer.limit();
            Logger.e(tag,"decode num :"+limit);
            byte[] bytes = new byte[limit];
            ioBuffer.get(bytes);
            我们的对象m = new 我们的对象();//把服务器数据读进来的是数组,要转为我们想看到的对象
            if (limit >= AppSocketHead.HEAD_LENGTH) {
                m.ResponseHeader = getHead(bytes);//返回的数组中读取信息头
                m.ResponseBody = getResponseBody(bytes);//返回的数组中读取信息体
            }
            protocolDecoderOutput.write(m);

        }
    }

}

设置心跳

就算服务器不是使用mina框架,你也可以使用mina的心跳模块,前提是服务器支持心跳监听。
设置使用心跳代码在上面写过,如下:

  //设置心跳工程
        KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();
         当读操作空闲时发送心跳
        KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory);
        // 设置心跳包请求后超时无反馈情况下的处理机制,默认为关闭连接,在此处设置为输出日志提醒
        heartBeat.setRequestTimeoutHandler(KeepAliveRequestTimeoutHandler.LOG);
        /** 是否回发 */
        heartBeat.setForwardEvent(false);
        /** 发送频率 */
        heartBeat.setRequestInterval(5);// 单位应该是秒
        /** 设置心跳包请求后 等待反馈超时时间。 超过该时间后则调用KeepAliveRequestTimeoutHandler.CLOSE */
        heartBeat.setRequestTimeout(15);//  单位应该是秒
        connector.getSessionConfig().setKeepAlive(true);
        connector.getFilterChain().addLast("heartbeat", heartBeat);

KeepAliveMessageFactoryImpl是实现KeepAliveMessageFactory接口的类,该类有以下方法:

//
Object  getRequest(IoSession session) 
Object  getResponse(IoSession session, Object request) 
boolean isRequest(IoSession session, Object message) 
boolean isResponse(IoSession session, Object message) 

下面是我的实现类,不多说,看注释就懂了:

public class KeepAliveMessageFactoryImpl implements KeepAliveMessageFactory {
    private String tag = "KeepAliveMessageFactoryImpl";
    private static final String ResponseStr = "keepalive_response";
    private static final String RequestStr = "keepalive_request";


    @Override
    public Object getRequest(IoSession session) {
        Logger.e(tag, "getRequest");
        return getKeepAliveData();//返回心跳请求数据
    }

    private AppSocketMessage getKeepAliveData() {
         //....你的服务器心跳需要的数据
        return m;
    }


    @Override
    public Object getResponse(IoSession session, Object request) {
        Logger.e(tag, "getResponse");
        return ResponseStr;//返回心跳请求返回数据,这里将数据进行处理封装成你想要的数据
    }


    //true if and only if the specified message is a keep-alive response message;
    @Override
    public boolean isRequest(IoSession session, Object message) {
        Logger.e(tag, "isRequest");
        AppSocketMessage sm = (AppSocketMessage) message;
        if (sm != null && sm.SendBody != null && sm.SendBody.equals(RequestStr)) {
            Logger.e(tag, "isRequest : 是请求心跳包");
            return true;
        }
        return false;
    }

   //true if and only if the specified message is a keep-alive request message.
    @Override
    public boolean isResponse(IoSession session, Object message) {
        Logger.e(tag, "isResponse");
        AppSocketMessage sm = (AppSocketMessage) message;
        if (sm != null && sm.ResponseBody != null && sm.ResponseBody.trim().equals(ResponseStr)) {
            Logger.e(tag, "isResponse : 是返回心跳包");
            return true;
        }
        return false;
    }


}

转载注明:http://blog.csdn.net/u014614038/article/details/78564838

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值