Always failed to close channel (netty) from server-side when the client has been physically killed

Junjie :

It's a web-socket application based on netty. However, when the client is physically killed without sending a CloseWebSocketFrame, server needs to know the channel has been closed and do some cleaning work. IdleStateHandler is used to monitor whether the channel is idle.

Here is the channel handler pipeline.

public void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
    SSLEngine sslEngine = new SSLServiceBase().getSSLContext().createSSLEngine();
    sslEngine.setUseClientMode(false);
    sslEngine.setNeedClientAuth(true);
    ... // business process
    pipeline.addLast(new IdleStateHandler(30, 10, 0, TimeUnit.SECONDS));
    pipeline.addLast(new HeartbeatHandler());
}

This is the userEventTriggered method of HeartbeatHandler which is used to do some cleaning work when channel is closed from the client abnormally.

public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    if (evt instanceof IdleStateEvent) {
        IdleStateEvent event = (IdleStateEvent) evt;
        if (IdleState.WRITER_IDLE.equals(event.state())) {
            ctx.writeAndFlush(new PingWebSocketFrame()).addListener(future -> {
                if (!future.isSuccess()) {
                    ChannelFuture closeFuture = ctx.channel().close();
                    if (closeFuture.isSuccess()) {
                        System.out.println("ping faild, channel close successfully");
                    } else {
                        System.out.println("ping failed, channel close failed");
                    }
                } else {
                    System.out.println("Ping succeed, keep the channel.");
                }
            });
        }
    } else {
        super.userEventTriggered(ctx, evt);
    }
}

Actually, I'm continuously getting 'close failed', and the channel is still alive from the server view. Could anyone let me know why the channel can't be closed or how to close? Thanks a lot.

Norman Maurer :

I suspect the close was not done yet (remember it is an async operation). Change the code to:

public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    if (evt instanceof IdleStateEvent) {
        IdleStateEvent event = (IdleStateEvent) evt;
        if (IdleState.WRITER_IDLE.equals(event.state())) {
            ctx.writeAndFlush(new PingWebSocketFrame()).addListener(future -> { 
                if (!future.isSuccess()) {
                    ctx.close().addListener(closeFuture -> {
                        If (closeFuture.isSuccess()) {
                            System.out.println("ping faild, channel close successfully");
                        } else {
                            System.out.println("ping failed, channel close failed");
                            // TODO: You may also want to log the reason why the close operation failed. 
                            //       closeFuture.cause() will contain why.
                        }
                    });                    
                } else {
                    System.out.println("Ping succeed, keep the channel.");
                }
        });
    }
} else {
    super.userEventTriggered(ctx, evt);
}

}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=417413&siteId=1
Recommended