Netty:使用 `IdleStateHandler` 检测断开连接
Netty: Using `IdleStateHandler` to detect disconnection
我阅读了 IdleStateHandler
的文档,并从我的服务器中实现了与文档相同的方法,
但我不明白如何准确判断客户端是否断开连接,例如客户端失去 Wifi 连接。
据我了解,在我的 Handler 中,方法 channelInactive()
是在客户端断开连接时触发的,
然后使用IdleStateHandler
,当在指定的时间段内没有执行读取时,将触发IdleState.READER_IDLE
,
然后在 3 秒没有从客户端读取后,我关闭了频道并期望 channelInactive
将被触发但它不是,为什么?
初始化程序
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
String TAG = "LOG: ";
@Override
protected void initChannel(SocketChannel ch) throws Exception {
System.out.println(TAG + "Starting ServerInitializer class...");
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast("encoder", new ObjectEncoder());
pipeline.addLast("idleStateHandler", new IdleStateHandler(6, 3, 0, TimeUnit.SECONDS));
pipeline.addLast("handler", new ServerHandler());
}
}
处理程序
public class ServerHandler extends ChannelInboundHandlerAdapter {
private String TAG = "LOG: ";
public ServerHandler(){}
@Override
public void channelActive(ChannelHandlerContext ctx) {
Log.w(TAG,"New Client become connected, Sending a message to the Client. Client Socket is: " + ctx.channel().remoteAddress().toString());
List<String> msg = new ArrayList<>();
msg.add(0,"sample message 1");
msg.add(1,"sample message 2");
sendMessage(ctx, msg);
}
public void sendMessage(ChannelHandlerContext ctx, List message){
ctx.write(message);
ctx.flush();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
Log.w(TAG,"A Client become disconnected. Client Socket is: " + ctx.channel().remoteAddress().toString() + " id: " + (String.valueOf(ctx.channel().hashCode())));
//COnnection id dead, do something here...
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object object) { // (2)
Log.w(TAG, "CLIENT: "+ ctx.channel().remoteAddress().toString() + " SAYS: " + object);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
// Close the connection for that client when an exception is raised.
Log.e(TAG,"Something's wrong, CLIENT: "+ ctx.channel().remoteAddress().toString() + " CAUSE: " + cause.toString());
ctx.close();
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
Log.w(TAG,"LOLO");
if (evt instanceof IdleStateEvent) {
IdleStateEvent e = (IdleStateEvent) evt;
if (e.state() == IdleState.READER_IDLE) {
ctx.close(); //Closed the Channel so that the `channelInactive` will be trigger
} else if (e.state() == IdleState.WRITER_IDLE) {
ctx.writeAndFlush("ping\n"); //Send ping to client
}
}
}
}
任何人都可以帮助我
IdleStateHandler
应该始终是管道中的第一个处理程序。
使用 ReadTimeoutHandler 而不是 IdleStateHandler 并覆盖 exceptionCaught 方法。
我阅读了 IdleStateHandler
的文档,并从我的服务器中实现了与文档相同的方法,
但我不明白如何准确判断客户端是否断开连接,例如客户端失去 Wifi 连接。
据我了解,在我的 Handler 中,方法 channelInactive()
是在客户端断开连接时触发的,
然后使用IdleStateHandler
,当在指定的时间段内没有执行读取时,将触发IdleState.READER_IDLE
,
然后在 3 秒没有从客户端读取后,我关闭了频道并期望 channelInactive
将被触发但它不是,为什么?
初始化程序
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
String TAG = "LOG: ";
@Override
protected void initChannel(SocketChannel ch) throws Exception {
System.out.println(TAG + "Starting ServerInitializer class...");
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast("encoder", new ObjectEncoder());
pipeline.addLast("idleStateHandler", new IdleStateHandler(6, 3, 0, TimeUnit.SECONDS));
pipeline.addLast("handler", new ServerHandler());
}
}
处理程序
public class ServerHandler extends ChannelInboundHandlerAdapter {
private String TAG = "LOG: ";
public ServerHandler(){}
@Override
public void channelActive(ChannelHandlerContext ctx) {
Log.w(TAG,"New Client become connected, Sending a message to the Client. Client Socket is: " + ctx.channel().remoteAddress().toString());
List<String> msg = new ArrayList<>();
msg.add(0,"sample message 1");
msg.add(1,"sample message 2");
sendMessage(ctx, msg);
}
public void sendMessage(ChannelHandlerContext ctx, List message){
ctx.write(message);
ctx.flush();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
Log.w(TAG,"A Client become disconnected. Client Socket is: " + ctx.channel().remoteAddress().toString() + " id: " + (String.valueOf(ctx.channel().hashCode())));
//COnnection id dead, do something here...
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object object) { // (2)
Log.w(TAG, "CLIENT: "+ ctx.channel().remoteAddress().toString() + " SAYS: " + object);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
// Close the connection for that client when an exception is raised.
Log.e(TAG,"Something's wrong, CLIENT: "+ ctx.channel().remoteAddress().toString() + " CAUSE: " + cause.toString());
ctx.close();
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
Log.w(TAG,"LOLO");
if (evt instanceof IdleStateEvent) {
IdleStateEvent e = (IdleStateEvent) evt;
if (e.state() == IdleState.READER_IDLE) {
ctx.close(); //Closed the Channel so that the `channelInactive` will be trigger
} else if (e.state() == IdleState.WRITER_IDLE) {
ctx.writeAndFlush("ping\n"); //Send ping to client
}
}
}
}
任何人都可以帮助我
IdleStateHandler
应该始终是管道中的第一个处理程序。
使用 ReadTimeoutHandler 而不是 IdleStateHandler 并覆盖 exceptionCaught 方法。