当客户端被物理杀死时,总是无法从服务器端关闭通道(netty)
Always failed to close channel (netty) from server-side when the client has been physically killed
这是一个基于 netty 的网络套接字应用程序。但是,当客户端在没有发送 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'
,并且从服务器视图来看频道仍然有效。谁能告诉我为什么不能关闭频道或如何关闭?非常感谢。
我怀疑关闭还没有完成(记住这是一个异步操作)。将代码更改为:
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);
}
}
这是一个基于 netty 的网络套接字应用程序。但是,当客户端在没有发送 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'
,并且从服务器视图来看频道仍然有效。谁能告诉我为什么不能关闭频道或如何关闭?非常感谢。
我怀疑关闭还没有完成(记住这是一个异步操作)。将代码更改为:
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);
}
}