Apache Mina心跳及断线重连

原理

客户端

package com.cnblogs.javalouvre;

import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoService;
import org.apache.mina.core.service.IoServiceListener;
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.textline.TextLineCodecFactory;
import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.filter.keepalive.KeepAliveRequestTimeoutHandler;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.mina.filter.codec.textline.LineDelimiter.WINDOWS;

public class Client {

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

    private static final String HOST  = "127.0.0.1";
    private static final int    PORT  = 5678;

    public static void main(String[] args) {
        final NioSocketConnector connector = new NioSocketConnector();

        // 获取socket会话配置
        final SocketSessionConfig sessionConfig = connector.getSessionConfig();
        sessionConfig.setKeepAlive(Boolean.TRUE);  // 长链接
        sessionConfig.setTcpNoDelay(Boolean.TRUE); // 低延迟

        // 过滤器链
        final DefaultIoFilterChainBuilder filterChain = connector.getFilterChain();
        // 编码、解码过滤器
        filterChain.addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(UTF_8, WINDOWS.getValue(), WINDOWS.getValue())));
        // 日志过滤器
        filterChain.addLast("logger", new LoggingFilter());
        // 心跳过滤器
        final KeepAliveFilter keepAliveFilter = new KeepAliveFilter(new KeepAliveMessageFactory() {

            @Override
            public boolean isRequest(IoSession session, Object message) {
                return true;
            }

            @Override
            public boolean isResponse(IoSession session, Object message) {
                return false;
            }

            @Override
            public Object getRequest(IoSession session) {
                return "0x10";
            }

            @Override
            public Object getResponse(IoSession session, Object request) {
                return null;
            }

        }, IdleStatus.WRITER_IDLE, KeepAliveRequestTimeoutHandler.NOOP, 10, 5);
        filterChain.addLast("heartBeat", keepAliveFilter);
        // 事件处理
        connector.setHandler(new NoopIoHandlerAdapter());
        // 添加重连监听
        connector.addListener(new ReconnectIoServiceListener(connector));
        final ConnectFuture future = connector.connect(new InetSocketAddress(HOST, PORT));
        // 阻塞直到和服务端连接成功
        future.awaitUninterruptibly();

        // connector.dispose();
    }

}

class ReconnectIoServiceListener implements IoServiceListener {

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

    private final NioSocketConnector connector;

    public ReconnectIoServiceListener(NioSocketConnector connector) {
        this.connector = connector;
    }

    @Override
    public void serviceActivated(IoService service) throws Exception {

    }

    @Override
    public void serviceIdle(IoService service, IdleStatus idleStatus) throws Exception {

    }

    @Override
    public void serviceDeactivated(IoService service) throws Exception {

    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {

    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {

    }

    @Override
    public void sessionDestroyed(IoSession session) throws Exception {
        while (true) {
            try {
                TimeUnit.SECONDS.sleep(3);
                ConnectFuture future = connector.connect();
                future.awaitUninterruptibly(); // 等待连接创建成功
                session = future.getSession(); // 获取会话
                if (session.isConnected()) {
                    log.info("断线重连[" + connector.getDefaultRemoteAddress().getHostName() + ":" + connector.getDefaultRemoteAddress().getPort() + "]成功");

                    break;
                }
            } catch (Exception e) {
                log.info("重连服务器登录失败,3秒再连接一次: {}", e.getMessage());
            }
        }
    }
}

服务端

package com.cnblogs.javalouvre;

import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.mina.filter.codec.textline.LineDelimiter.WINDOWS;

public class Server {

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

    private static final int PORT  = 5678;

    private void bind() {
        final NioSocketAcceptor acceptor = new NioSocketAcceptor();
        // 过滤器链
        final DefaultIoFilterChainBuilder filterChain = acceptor.getFilterChain();
        // 编码、解码过滤器
        filterChain.addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(UTF_8, WINDOWS.getValue(), WINDOWS.getValue())));
        // 日志过滤器
        filterChain.addLast("logger", new LoggingFilter());
        // 获取socket会话配置
        final SocketSessionConfig sessionConfig = acceptor.getSessionConfig();
        // 设置缓存大小
        sessionConfig.setReadBufferSize(1024);
        // 设置读空闲时间10秒
        sessionConfig.setIdleTime(IdleStatus.READER_IDLE, 10);
        // 事件处理
        acceptor.setHandler(new NoopIoHandlerAdapter());

        try {
            // 绑定端口
            acceptor.bind(new InetSocketAddress(PORT));
        } catch (IOException e) {
            e.printStackTrace();
        }

        log.info("端口 {} 启动成功", PORT);
    }

    public static void main(String[] args) {
        new Server().bind();
    }

}

消息处理

package com.cnblogs.javalouvre;

import org.apache.mina.core.service.IoHandlerAdapter;

public class NoopIoHandlerAdapter extends IoHandlerAdapter {
}
posted @ 2022-05-06 17:43  Bruce.Chang.Lee  阅读(206)  评论(0编辑  收藏  举报