Mina的使用

1.下载jar包:点击打开链接

2.实现心跳

public class KeepAliveClientImpl implements KeepAliveMessageFactory {

    public static final String REQUEST_HEART = "1";//请求
    public static final String RESPONSE_HEART = "2";//响应

    @Override
    public boolean isRequest(IoSession ioSession, Object o) {
        if (o instanceof String) {
            String s = (String) o;
            if (s.equals(REQUEST_HEART)) {//服务端判断是否是心跳请求
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isResponse(IoSession ioSession, Object o) {
        if (o instanceof String) {
            String s = (String) o;
            if (s.equals(RESPONSE_HEART)) {//客户端判断是否是心跳响应
                return true;
            }
        }
        return false;
    }

    @Override
    public Object getRequest(IoSession ioSession) {//客户端主动发起心跳请求
        return REQUEST_HEART;
    }

    @Override
    public Object getResponse(IoSession ioSession, Object o) {//服务器响应心跳请求
        return RESPONSE_HEART;
    }
}

3.自定义编解码

编码

public class JavaProtobufEncoderFactory extends ProtocolEncoderAdapter {
    @Override
    public void encode(IoSession ioSession, Object message, ProtocolEncoderOutput out) throws Exception {

        String s = (String) message;
        byte[] bytes = s.getBytes("utf-8");
        int length = bytes.length;

        int packageLength = length + 4;//java中int类型占4个字节

        System.out.println("package ==" + packageLength);
        IoBuffer buffer = IoBuffer.allocate(packageLength);
        buffer.putInt(length); // write header
        buffer.put(bytes); // write body
        buffer.flip();
        out.write(buffer);
    }

}

解码

public class JavaProtobufDecoderFactory extends CumulativeProtocolDecoder {

    private final static Logger log = LoggerFactory
            .getLogger(JavaProtobufDecoderFactory.class);

    @Override
    protected boolean doDecode(IoSession ioSession, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
        // 如果没有接收完Header部分(4字节),直接返回false

        System.out.println("byte----->in.remaining==" + in.remaining());

        int packageLength = 4;

        if (in.remaining() <= packageLength) {
            return false;
        } else {

            // 标记开始位置,如果一条消息没传输完成则返回到这个位置
            in.mark();

            // 读取header部分,获取body长度
            int bodyLength = in.getInt();
            log.info("bodyLength==" + bodyLength);

            // 如果body没有接收完整,直接返回false
            int remaining = in.remaining();//注意:这里是从第header读完开始(假设刚开始in.remaining()==8,这里就是in.remaining()==4)
            if (remaining < bodyLength) {
                in.reset(); // IoBuffer position回到原来标记的地方
                return false;
            } else {
                byte[] bodyBytes = new byte[bodyLength];
                in.get(bodyBytes); // 读取body部分

                String s = new String(bodyBytes);
                out.write(s); // 解析出一条消息
                return true;
            }
        }
    }
    
}

4.创建客户端

public class MinaClient {
    public static void main(String[] agb) {
        NioSocketConnector connector = new NioSocketConnector();//TCP连接
        //设置编码器
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ProtobufFactory()));
        /*
        * 设置心跳
        * */
        KeepAliveClientImpl keepAliveClient = new KeepAliveClientImpl();
        KeepAliveFilter mKeepAliveFilter = new KeepAliveFilter(keepAliveClient, IdleStatus.BOTH_IDLE, new KeepAliveRequestTimeoutHandler() {
            @Override
            public void keepAliveRequestTimedOut(KeepAliveFilter keepAliveFilter, IoSession ioSession) throws Exception {
                System.out.println("time out --------------");
            }
        });
        mKeepAliveFilter.setForwardEvent(true);//说明:继续调用 IoHandlerAdapter 中的 sessionIdle时间
        mKeepAliveFilter.setRequestInterval(20);//说明:设置当连接的读取通道空闲的时候,心跳包请求时间间隔
        mKeepAliveFilter.setRequestTimeout(5);//说明:设置心跳包请求后 等待反馈超时时间。 超过该时间后则调用KeepAliveRequestTimeoutHandler.CLOSE
        connector.getFilterChain().addLast("heart", mKeepAliveFilter);

        connector.setHandler(new ClientHandler());//消息回调
        ConnectFuture connect = connector.connect(new InetSocketAddress("你的ip地址", 9000));//连接
        connect.awaitUninterruptibly();//同步等待,session创建成功为止

        connect.getSession().write("hello world");//发送字符串消息(如果实际项目是传递对象,要根据需求调整编解码)

    }


    public static class ClientHandler extends IoHandlerAdapter {

        public ClientHandler() {
        }

        @Override
        public void sessionOpened(IoSession session) {//通道打开
        }

        @Override
        public void sessionIdle(IoSession session, IdleStatus status) throws Exception {//空闲状态
            super.sessionIdle(session, status);
        }

        @Override
        public void messageSent(IoSession session, Object message) throws Exception {//消息已经发出
            super.messageSent(session, message);
        }

        @Override
        public void messageReceived(IoSession session, Object message) throws Exception {//接收到消息
            super.messageReceived(session, message);
        }

        @Override
        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {//异常
            super.exceptionCaught(session, cause);
        }

        @Override
        public void sessionClosed(IoSession session) throws Exception {//session关闭
            super.sessionClosed(session);
        }

        @Override
        public void sessionCreated(IoSession session) throws Exception {//欣创建session
            super.sessionCreated(session);
        }
    }
}

5.创建服务端

public class MinaService {
    public static void main(String[] arg) {
        NioSocketAcceptor acceptor = new NioSocketAcceptor();
        acceptor.getSessionConfig().setReadBufferSize(2048);//设置读取缓冲大小
        acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);//
        acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ProtobufFactory()));

        //心跳机制
        KeepAliveClientImpl mKeepAliveService = new KeepAliveClientImpl();
        KeepAliveFilter mKeepAliveFilter = new KeepAliveFilter(mKeepAliveService, IdleStatus.BOTH_IDLE, new KeepAliveRequestTimeoutHandler() {
            @Override
            public void keepAliveRequestTimedOut(KeepAliveFilter keepAliveFilter, IoSession ioSession) throws Exception {
                System.out.println("time out --------------");
            }
        });
        mKeepAliveFilter.setForwardEvent(true); //idle事件回发  当session进入idle状态的时候 依然调用handler中的idled方法
        //说明:尤其 注意该句话,使用了 KeepAliveFilter之后,IoHandlerAdapter中的 sessionIdle方法默认是不会再被调用的! 所以必须加入这句话 sessionIdle才会被调用

        mKeepAliveFilter.setRequestInterval(30);  //本服务器为被定型心跳  即需要每30秒接受一个心跳请求  否则该连接进入空闲状态 并且发出idled方法回调
        // 说明:设置心跳包请求时间间隔,其实对于被动型的心跳机制来说,设置心跳包请求间隔貌似是没有用的,因为它是不会发送心跳包的,但是它会触发 sessionIdle事件, 我们利用该方法,可以来判断客户端是否在该时间间隔内没有发心跳包,一旦 sessionIdle方法被调用,则认为 客户端丢失连接并将其踢出 。因此其中参数 heartPeriod其实就是服务器对于客户端的IDLE监控时间。
        mKeepAliveFilter.setRequestTimeout(5); //超时时间   如果当前发出一个心跳请求后需要反馈  若反馈超过此事件 默认则关闭连接
        acceptor.getFilterChain().addLast("heart", mKeepAliveFilter);

        acceptor.setHandler(new MyIoHandler());
        try {
            acceptor.bind(new InetSocketAddress(9000));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static class MyIoHandler extends IoHandlerAdapter {


        @Override
        public void messageReceived(IoSession session, Object message)
                throws Exception {//接收到消息
            System.out.println("messageReceived==" + message.toString());
        }

        @Override
        public void messageSent(IoSession session, Object message) throws Exception {//消息已发送
            super.messageSent(session, message);
        }

        @Override
        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
            super.exceptionCaught(session, cause);
        }

        @Override
        public void sessionCreated(IoSession session) throws Exception {
            super.sessionCreated(session);
        }

        @Override
        public void sessionOpened(IoSession session) throws Exception {
            super.sessionOpened(session);
        }

        @Override
        public void sessionClosed(IoSession session) throws Exception {
            super.sessionClosed(session);
        }

        @Override
        public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
            super.sessionIdle(session, status);
            System.out.println("sessionIdle");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值