当客户端被物理杀死时,总是无法从服务器端关闭通道(netty)
Posted
技术标签:
【中文标题】当客户端被物理杀死时,总是无法从服务器端关闭通道(netty)【英文标题】:Always failed to close channel (netty) from server-side when the client has been physically killed 【发布时间】:2020-05-29 20:53:27 【问题描述】:这是一个基于 netty 的 web-socket 应用。但是,当客户端在没有发送CloseWebSocketFrame
的情况下被物理杀死时,服务器需要知道通道已关闭并进行一些清理工作。 IdleStateHandler
用于监控通道是否空闲。
这是通道处理程序管道。
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());
这是HeartbeatHandler
的userEventTriggered
方法,用于在客户端异常关闭通道时做一些清理工作。
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);
实际上,我不断收到'close failed'
,并且从服务器视图来看,该频道仍处于活动状态。谁能告诉我为什么无法关闭频道或如何关闭?非常感谢。
【问题讨论】:
【参考方案1】:我怀疑关闭还没有完成(记住这是一个异步操作)。将代码更改为:
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);
【讨论】:
我阅读了ChannelFuture
的大多数方法,但我错过了cause()
。实际上在ChannelHandler
之一的方法void close(ChannelHandlerContext ctx, ChannelPromise promise)
中发生了异常,因此通道无法在不打印消息的情况下关闭。这是正确的答案。以上是关于当客户端被物理杀死时,总是无法从服务器端关闭通道(netty)的主要内容,如果未能解决你的问题,请参考以下文章
当客户端关闭连接时,Cowboy/Ranch 杀死处理程序进程