Introduction

In the process of using the client and server connections, the connection between the client and the server may be interrupted due to various problems. In this case, we generally need to use a monitoring program to monitor the client and server Connection, if you find that the connection is disconnected the first time, you need to manually reconnect. It's more troublesome. Today, I will introduce you a way to automatically reconnect in netty.

Use netty to establish a connection

To use netty to establish a connection, you first need to start the server. Generally speaking, the server starts the server by using ServerBootstrap, as shown below:

// 绑定端口并启动
ChannelFuture f = b.bind(PORT).sync();

For the client, it can be started by Bootstrap as follows:

// 连接服务器
ChannelFuture f = b.connect(HOST, PORT).sync();

Principle of automatic reconnection

So when the connection between the client and the server is broken, how to automatically reconnect?

For the client, automatic reconnection only needs to call Bootstrap's connect method again. The key question now is how to find the time to call connect again.

We know that no matter the server or the client, the processing of messages requires the registration of a handler that specializes in processing messages.

For reading messages, it is generally necessary to inherit the ChannelInboundHandlerAdapter. In this handler, many methods related to the channel life cycle are defined. We can start with these life cycle methods.

Generally speaking, the status of the connection between the client and the server is this:

CHANNEL REGISTERED--》CHANNEL ACTIVE --》 READ --》READ COMPLETE --》 CHANNEL INACTIVE --》 CHANNEL UNREGISTERED

If the connection between the client and the server is closed, it will trigger the CHANNEL INACTIVE and CHANNEL UNREGISTERED events, so we rewrite the following two methods on the client side and add the reconnection logic in the method.

    @Override
    public void channelInactive(final ChannelHandlerContext ctx) {
        println("连接断开:" + ctx.channel().remoteAddress());
    }

    @Override
    public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {
        println("sleep:" + ReconnectClient.RECONNECT_DELAY + 's');

        ctx.channel().eventLoop().schedule(() -> {
            println("重连接: " + ReconnectClient.HOST + ':' + ReconnectClient.PORT);
            ReconnectClient.connect();
        }, ReconnectClient.RECONNECT_DELAY, TimeUnit.SECONDS);
    }

In the channelInactive method, we just printed some logs. The main logic is in the channelUnregistered method. In this method, we first get the current channel through ctx, then get the eventLoop in the channel, then call its schedule method, and call the connect() method again after a given time.

The connect() method returns a ChannelFuture, so you can add some listeners to the ChannelFuture to monitor the execution status of connect.

The connect method defined here is as follows:

    static void connect() {
        bs.connect().addListener(future -> {
            if (future.cause() != null) {
                handler.startTime = -1;
                handler.println("建立连接失败: " + future.cause());
            }
        });
    }

Simulate automatic reconnection

We already know how to automatically reconnect in the previous section. This section will simulate the automatic reconnection.

Here is a class called IdleStateHandler. It can be seen from the name that this class will trigger the Idle state when the Channel does not perform any read or write operations.

The class that represents the Idle state is called IdleStateEvent. Idle has 6 states, namely FIRST_READER_IDLE_STATE_EVENT, READER_IDLE_STATE_EVENT, FIRST_WRITER_IDLE_STATE_EVENT, WRITER_IDLE_STATE_EVENT, FIRST_ALL_IDLE_STATE_EVENT and ALL_IDLE_STATE_EVENT.

Represents the IDLE in the read state, the IDLE in the write state and the IDLE in the read and write state respectively.

In this way, we can add IdleStateHandler when the client is started. When the client has not read the message from the server for a period of time, we call ctx.close() to close the channel and start the client reconnection operation.

        bs.group(group)
                .channel(NioSocketChannel.class)
                .remoteAddress(HOST, PORT)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new IdleStateHandler(READ_TIMEOUT, 0, 0), handler);
                    }
                });

IdleStateEvent is an event initiated by a user. To capture this event, userEventTriggered needs to be rewritten:

    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (!(evt instanceof IdleStateEvent)) {
            return;
        }
        IdleStateEvent e = (IdleStateEvent) evt;
        if (e.state() == IdleState.READER_IDLE) {
            // 在Idle状态
            println("Idle状态,关闭连接");
            ctx.close();
        }
    }

In the above example, we captured IdleStateEvent and judged that if the state of IdleState is IdleState.READER_IDLE, then the channel will be closed.

Summarize

In this article, we have introduced the principle of reconnection and user-triggered events. I hope you will enjoy them.

For the examples in this article, please refer to: learn-netty4

This article has been included in http://www.flydean.com/09-netty-reconnect/

The most popular interpretation, the most profound dry goods, the most concise tutorial, and many tips you don't know are waiting for you to discover!

Welcome to pay attention to my official account: "Program those things", know technology, know you better!


flydean
890 声望433 粉丝

欢迎访问我的个人网站:www.flydean.com