Netty - 处理 AnnotatedConnectException

Netty - Handle AnnotatedConnectException

我是网络库和 Netty 的新手,我正在构建客户端。从我的测试中,我知道我的代码可以按预期正常工作,但是我想在它无法正确连接到主机时提供更有意义的消息。所以我所做的是尝试让它连接到端口的本地主机,但我没有托管在那里,所以它会抛出异常。下面是堆栈跟踪:

Exception in thread "main" io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8484
    at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
    at sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source)
    at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:353)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:340)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:633)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
    at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:858)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.net.ConnectException: Connection refused: no further information
    ... 11 more

我尝试尝试捕获 AnnotatedConnectException,但是似乎没有任何导入 class。我怀疑这个 class 是 AbstractChannel 中的私有异常。我检查了实现,它是:

private static final class AnnotatedConnectException extends ConnectException {

    private static final long serialVersionUID = 3901958112696433556L;

    AnnotatedConnectException(ConnectException exception, SocketAddress remoteAddress) {
        super(exception.getMessage() + ": " + remoteAddress);
        initCause(exception);
        setStackTrace(exception.getStackTrace());
    }

    @Override
    public Throwable fillInStackTrace() {
        return this;
    }
}

我还发现我可以通过使用 Exception 进行 try-catch 来处理这个异常。但是,如果可能的话,我想避免这种情况,因为我觉得这是一个糟糕的主意。关于是否可以做到以及如何做到的任何想法?

编辑:这是我尝试捕获 ConnectException(对 AnnotatedConnectException 尝试了同样的事情。这是在 ConnectException 所在的地方完成的):

 public void connectToServer(String host, int port) {
Bootstrap bootstrap = new Bootstrap();
/*
 * Creates/configures the handler group which will handle the connection and keep the connection
 * alive.
 */
EventLoopGroup handlerGroup = new NioEventLoopGroup();
bootstrap.group(handlerGroup).channel(NioSocketChannel.class)
    .option(ChannelOption.SO_KEEPALIVE, true).handler(new ChannelInitializer<SocketChannel>() {
      @Override
      protected void initChannel(SocketChannel socketChannel) {
        /*
         * Handles a connection when it is connected (ie. decoding/encoding packets and
         * handling the packets that the server sends back to the client).
         */
        socketChannel.pipeline().addLast("MapleProtocolDecoder", new MapleProtocolDecoder());
        socketChannel.pipeline().addLast("ServerHandler", new ServerHandler());
        socketChannel.pipeline().addLast("MapleProtocolEncoder", new MapleProtocolEncoder());
      }
    });

try {
  // Connects the client
  ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
  // Waits until the connection is closed
  channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
  handlerGroup.shutdownGracefully();
  System.out.println("[Info] The client has disconnected!");
} catch (ConnectException e) {
  System.out.println( e.getClass().getCanonicalName()); 
  System.out.println("[Info] The server is offline."); 
}

}

谢谢!

该库可能由您的容器在运行时提供,并且在开发过程中您可能无法使用,除非专门将其添加到项目的类路径中。但是您不一定要这样做,因为它会在您的项目上创建对低级容器实现细节的依赖。在这种情况下,如果您最终部署到另一个应用程序服务器(tomcat、jboss、weblogic 等),netty 库可能仅在本地开发期间存在。

我建议简单地捕获 AnnotatedConnectException 扩展的更通用的 ConnectExceptionConnectException 是标准 Java JDK 的一部分,因此不需要额外的类路径修改,并且可以跨所有应用程序服务器移植。

你认为捕获异常不是一个好主意是正确的。最好只捕获您尝试执行的代码将抛出的特定异常,以便您可以向用户或在您的日志中显示更准确的消息。 This article 关于异常处理技术可能会有用。

编辑:

如果您调用的框架没有指明可以抛出 ConnectException,那么您可能被迫捕获异常:

    try {
        // your code
    } catch (InterruptedException e) {
       // Do something
    } catch (Exception e) {
       // Do something else 
    }

这并不理想,但框架 API 让你别无选择。

删除 sync() 并使用侦听器处理连接的成功或失败。

try {
    ChannelFuture channelFuture = bootstrap.connect(host, port);
    channelFuture.addListener(f -> {
        if (!f.isSuccess() && f.cause() instanceof ConnectException) {
            System.out.println("[Info] The server is offline.");
        }
    });
    channelFuture.await();
} catch (InterruptedException e) {
    e.printStackTrace();
}