Java(Bukkit) Netty 客户端在第二个线程中启动时停止工作

Java(Bukkit) Netty Client stops working when started in second thread

我 运行 在开发我的软件时遇到了问题。

我有一个 Netty 服务器和多个 Netty 客户端。但是,当我尝试在新线程中启动它们时,它们会在出现一些调试消息后停止。客户端在 Bukkit 上运行,Bukkit 是一种 Minecraft 服务器软件。其他东西的其他客户端在独立的 java 程序上运行,它们工作得很好。

这是我的客户class:

public class NettyClient extends Thread {

public boolean connected;


/**
 * Returns true if the client is connected.
 *
 * @return boolean
 */

String host;
int port;
public Channel channel;
public BlockingQueue<Packet> queue = new LinkedBlockingDeque<>();


public NettyClient(String host, int port) {
    this.host = host;
    this.port = port;
}


@Override
public void run() {
    boolean epoll = Epoll.isAvailable();
    System.out.println("[Sys] Server-Typ: " + (epoll ? "Epoll" : "Nio"));
    EventLoopGroup mainEventLoopGroup = epoll ? new EpollEventLoopGroup() : new NioEventLoopGroup();

    Bootstrap bootstrap = new Bootstrap();


    try {
        bootstrap.group(mainEventLoopGroup)
                .channel(epoll ? EpollSocketChannel.class : NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(final SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast("encoder", new PacketEncoder());
                        socketChannel.pipeline().addLast("decoder", new PacketDecoder());
                        socketChannel.pipeline().addLast("wrapperhandler", new WrapperHandler());
                    }
                });
        ChannelFuture f = bootstrap.connect(host, port).channel().closeFuture().syncUninterruptibly();
        this.channel = f.channel();
        System.out.println("Succesfully established connection to the wrapper server!");
       channel.writeAndFlush(new PacketServerLogIn(System.getProperty("servername"),System.getProperty("servergroup"), Bukkit.getServer().getIp(),Bukkit.getOnlinePlayers().size(),Bukkit.getMaxPlayers(),ServerState.WAITING));
      RedisBuilder.getInstance().startUpdateScheduler();


    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        mainEventLoopGroup.shutdownGracefully();

    }
}




public String getHost() {
    return host;
}

public int getPort() {
    return port;
}

public Channel getChannel() {
    return channel;
}
public boolean isConnected() {
    return connected;
}

}

这是我的服务器:

public class 网络服务器 {

String host;
int port;

public NetworkServer(String host, int port) {
    this.host = host;
    this.port = port;
}


public void run() {
    boolean epoll = Epoll.isAvailable();
    System.out.println("[Sys] Server-Typ: " + (epoll ? "Epoll" : "Nio"));
    EventLoopGroup mainEventLoopGroup = epoll ? new EpollEventLoopGroup(2) : new NioEventLoopGroup(2);
    EventLoopGroup workerEventLoopGroup = epoll ? new EpollEventLoopGroup(2) : new NioEventLoopGroup(2);
    ServerBootstrap serverBootstrap = new ServerBootstrap();

    try {
        serverBootstrap.group(mainEventLoopGroup, workerEventLoopGroup)
                .channel(epoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(final SocketChannel socketChannel) throws Exception {
                        final SSLContext sslContext = SSLFactory.createAndInitSSLContext("client.jks");
                        final SSLEngine sslEngine = sslContext.createSSLEngine();
                        sslEngine.setUseClientMode(false);
                        sslEngine.setEnabledCipherSuites(sslContext.getSocketFactory().getSupportedCipherSuites());

                        socketChannel.pipeline().addLast("ssl", new SslHandler(sslEngine));
                        //  socketChannel.pipeline().addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
                        //socketChannel.pipeline().addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
                        socketChannel.pipeline().addLast("decoder", new PacketDecoder());
                        socketChannel.pipeline().addLast("encoder", new PacketEncoder());
                        socketChannel.pipeline().addLast("wrapperhandler", new WrapperHandler());
                    }
                });
        serverBootstrap.bind(port).channel().closeFuture().sync();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        mainEventLoopGroup.shutdownGracefully();
        workerEventLoopGroup.shutdownGracefully();
    }
}


public String getHost() {
    return host;
}

public int getPort() {
    return port;
}

}

我认为 Bukkit 不喜欢多线程,但如果我错了请纠正我。

我的Netty版本是:4.1.2.Final

您的问题是因为您正在调用 .shutdownGracefully();,这基本上是在告诉 Netty 线程和通道它们应该关闭。

由于您正在开发 BUkkit 插件,因此您应该只在插件的 onDisable() 部分调用这些方法。

对于所有遇到此错误的人:我找到了解决方案。

您需要使用 maven 才能编译正确的 Netty 版本。

 <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <configuration>
                <createDependencyReducedPom>false</createDependencyReducedPom>
                <shadedArtifactAttached>true</shadedArtifactAttached>
                <relocations>
                    <relocation>
                        <pattern>io.netty</pattern>
                        <shadedPattern>io.nettynew</shadedPattern>
                    </relocation>
                </relocations>
            </configuration>
            <executions>

                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

这会将正确的 netty 版本重新着色到您的最终 jar 中,您现在可以毫无问题地连接到另一个 netty 服务器。确保你添加了 Netty 依赖到 maven:

<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.29.Final</version>