简体   繁体   English

当客户端被物理杀死时,总是无法从服务器端关闭通道(netty)

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

It's a web-socket application based on netty.它是一个基于 netty 的 web-socket 应用程序。 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.然而,当客户端在没有发送CloseWebSocketFrame情况下被物理杀死时,服务器需要知道通道已经关闭并做一些清理工作。 IdleStateHandler is used to monitor whether the channel is idle. IdleStateHandler用于监控通道是否空闲。

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.这是HeartbeatHandleruserEventTriggered方法,用于在客户端异常关闭通道时做一些清理工作。

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.实际上,我不断收到'close failed' ,并且从服务器的角度来看,该频道仍然存在。 Could anyone let me know why the channel can't be closed or how to close?谁能告诉我为什么无法关闭频道或如何关闭? Thanks a lot.非常感谢。

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);
}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM