user1990278
user1990278

Reputation: 13

How to reconnect to a server after the server stopped serving request in Netty IO

My netty IO client should keep trying to connect to a server whenever the server is restarted or the existing connection is broken. To implement this my client creates a new thread for establishing a new connection whenever the ChannelInActive callback method of my ChannelInboundHandlerAdapter is invoked. But my client throws the below error while establishing a new connection.

Exception in thread "main" io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8888 at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) at sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source) at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:325) at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:340) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:633) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Unknown Source) Caused by: java.net.ConnectException: Connection refused: no further information ... 11 more

Below lines are the run part of my connection thread.

EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group);
bootstrap.channel(NioSocketChannel.class).handler(new 
ChannelInitializer<SocketChannel>() {

        protected void initChannel(SocketChannel socketChannel) throws 
Exception {
            socketChannel.pipeline().addLast(new 
LengthFieldBasedFrameDecoder(64 * 1024, 0, 2));
            socketChannel.pipeline().addLast(ClientHandler);
        }

    });
    bootstrap.option(ChannelOption.SO_REUSEADDR,true);
    ChannelFuture channelFuture=null;
try 
{
    channelFuture = bootstrap.connect(new InetSocketAddress(IP, 
port)).sync();      
    channelFuture.awaitUninterruptibly();
    channelFuture.addListener(new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture channelFuture)
         {
        try
        {
            if (channelFuture.isSuccess()) {
            if(connectfuture!=null) connectfuture.cancel(true);log.debug("Cancelled connection thread scheduler");

        } else {
            channelFuture.cause().printStackTrace();
        connectfuture=channelFuture.channel().eventLoop().scheduleAtFixedRate(new ClientConnectorThread(ClientHandler,IP,port) , 5,30, TimeUnit.SECONDS);
        }
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
        }
        } );

}

catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

Upvotes: 0

Views: 1732

Answers (1)

Isuru
Isuru

Reputation: 722

When I want to implement re-connection logic, I do it as follows

Add two handlers for pipeline for capturing idle state

pipeline.addLast(new ReadTimeoutHandler(readTimeout, TimeUnit.SECONDS));
pipeline.addLast("ReconnectionHandler", new ReconnectionHandler());

In ReconnectionHandler capture the user event fired by ReadTimeoutHandler, disconnect the channel and try to reconnect

public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
    if (evt instanceof IdleStateEvent) {
        IdleStateEvent e = (IdleStateEvent) evt;
        if (e.state() == IdleState.READER_IDLE) {
            ctx.close();
        }
    } else {
        ctx.fireUserEventTriggered(evt);
    }
}

public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {
    final EventLoopGroup eventLoopGroup = ctx.channel().eventLoop().parent();
    eventLoopGroup.schedule(() -> {
        bootstrap.connect()
    }, reconnectDelay, TimeUnit.SECONDS);
    ctx.fireChannelUnregistered();
}

Upvotes: 0

Related Questions