面试题答案
一键面试Netty处理常见I/O异常的机制
- ChannelHandler的exceptionCaught方法:Netty通过在
ChannelHandler
中提供exceptionCaught
方法来处理在ChannelPipeline
中传播的异常。当I/O操作发生异常时,异常会被传递到ChannelPipeline
,并调用各个ChannelHandler
的exceptionCaught
方法。可以在该方法中进行日志记录、关闭连接、重连等操作。 - IdleStateHandler:用于处理连接超时。它可以设置读空闲时间、写空闲时间以及所有类型空闲时间,当达到设定的空闲时间时,会触发
IdleStateEvent
事件,用户可以在对应的ChannelHandler
中处理该事件,例如关闭连接或发起重连。 - 超时设置:在
Bootstrap
或ServerBootstrap
中可以设置连接超时时间,如bootstrap.connect(InetSocketAddress("127.0.0.1", 8080)).sync().channel().closeFuture().sync();
中的连接操作就会在设定的超时时间内尝试连接,如果超时未连接成功则抛出异常。
捕获和处理连接超时异常的实际代码示例
- 服务端代码
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyServer {
private int port;
public NettyServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 这里添加业务处理器
}
});
ChannelFuture f = b.bind(port).sync();
System.out.println("Server started, listening on port " + port);
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new NettyServer(8080).run();
}
}
- 客户端代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.ConnectTimeoutHandler;
import java.util.concurrent.TimeUnit;
public class NettyClient {
private String host;
private int port;
public NettyClient(String host, int port) {
this.host = host;
this.port = port;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ConnectTimeoutHandler(5, TimeUnit.SECONDS)); // 设置连接超时为5秒
// 这里添加业务处理器
}
});
ChannelFuture f = b.connect(host, port).sync();
System.out.println("Client connected to server");
f.channel().closeFuture().sync();
} catch (Exception e) {
if (e instanceof java.util.concurrent.TimeoutException) {
System.out.println("Connection timed out");
} else {
e.printStackTrace();
}
} finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new NettyClient("127.0.0.1", 8080).run();
}
}
在上述客户端代码中,通过pipeline.addLast(new ConnectTimeoutHandler(5, TimeUnit.SECONDS));
设置了连接超时为5秒,当连接超过5秒未成功时,会抛出java.util.concurrent.TimeoutException
,在catch
块中可以捕获并处理该异常,这里简单打印了连接超时信息。