Server Netty客户端与服务器连接,但服务器未激活/注册通道

Server Netty客户端与服务器连接,但服务器未激活/注册通道,server,connection,client,client-server,netty,Server,Connection,Client,Client Server,Netty,我使用了以下体系结构: - [Client] - The enduser connecting to our service. - [GameServer] - The game server on which the game is running. - [GameLobby] - A server that is responsible for matching Clients with a GameServer. 例如,如果我们有4个客户端想要玩游戏并与GameLobble匹配,那么第一

我使用了以下体系结构:

- [Client] - The enduser connecting to our service.
- [GameServer] - The game server on which the game is running.
- [GameLobby] - A server that is responsible for matching Clients with a GameServer.
例如,如果我们有4个客户端想要玩游戏并与GameLobble匹配,那么第一次所有这些连接都会成功

但是,当他们决定重新匹配时,其中一个客户端将无法正确连接

所有客户端和游戏服务器之间的连接同时发生

首先重新匹配的客户端将删除与游戏服务器的当前连接,然后再次进入大厅

此连接将成功,不会引发任何错误。即使使用ChannelFuture,也会显示客户端连接正确,检索以下值以显示客户端认为连接正确:

- ChannelFuture.isSuccess() = True
- ChannelFuture.isDone() = True
- ChannelFuture.cause() = Null
- ChannelFuture.isCancelled() = False
- Channel.isOpen() = True
- Channel.isActive() = True
- Channel.isRegistered() = True
- Channel.isWritable() = True
因此,根据客户机正确地进行了连接。但是,在SimpleChannelInboundHandler的游戏服务器上,从未为该特定客户端调用ChannelRegistered/ChannelActive方法。仅适用于其他3个客户端

所有4个客户端、游戏服务器和大厅都在同一个IP地址上运行

因为它只发生在(重新)连接到GameServer时,我认为这与没有正确关闭连接有关。目前,这是通过:

try {
    group.shutdownGracefully();
    channel.closeFuture().sync();
} catch (InterruptedException e) {
    e.printStackTrace();
}
在游戏服务器上,ChannelUnregister被调用,因此这是有效的,并且连接被破坏

我已经尝试过向故障通道连接的通道未来添加侦听器,但是根据通道未来,一切正常,事实并非如此

我尝试添加ChannelOptions以允许更多的客户端排队到服务器

游戏服务器 GameServer服务器初始化如下:

// Create the bootstrap to make this act like a server.
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup)
        .channel(NioServerSocketChannel.class)
        .childHandler(new ChannelInitialisation(new ClientInputReader(gameThread)))
        .option(ChannelOption.SO_BACKLOG, 1000)
        .childOption(ChannelOption.SO_KEEPALIVE, true)
        .childOption(ChannelOption.TCP_NODELAY, true);

bossGroup.execute(gameThread); // Executing the thread that handles all games on this GameServer.

// Launch the server with the specific port.
serverBootstrap.bind(port).sync();
GameServer客户端导入程序

@ChannelHandler.Sharable
public class ClientInputReader extends SimpleChannelInboundHandler<Packet> {
    private ServerMainThread serverMainThread;

    public ClientInputReader(ServerMainThread serverMainThread) {
        this.serverMainThread = serverMainThread;
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("[Connection: " + ctx.channel().id() + "] Channel registered");
        super.channelRegistered(ctx);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Packet packet) {
        // Packet handling
    }
}
客户初始化:

public class ChannelInitialisation extends ChannelInitializer<SocketChannel> {
    private SimpleChannelInboundHandler<Packet> channelHandler;

    ChannelInitialisation(SimpleChannelInboundHandler<Packet> channelHandler) {
        this.channelHandler = channelHandler;
    }

    @Override
    public void initChannel(SocketChannel ch) throws Exception {
        // prefix messages by the length
        ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
        ch.pipeline().addLast(new LengthFieldPrepender(4));

        // our encoder, decoder and handler
        ch.pipeline().addLast(new PacketEncoder(), new PacketDecoder(), channelHandler);

    }
}
公共类ChannelInitialization扩展了ChannelInitializer{
私有SimpleChannelInboundHandler channelHandler;
ChannelInitialization(SimpleChannelInboundHandler channelHandler){
this.channelHandler=channelHandler;
}
@凌驾
public void initChannel(SocketChannel ch)引发异常{
//按长度为消息添加前缀
ch.pipeline().addLast(新的LengthFieldBasedFrameDecoder(Integer.MAX_值,0,4,0,4));
ch.pipeline().addLast(新的LengthFieldPrepender(4));
//我们的编码器、解码器和处理器
ch.pipeline().addLast(新的PacketEncoder(),新的PacketDecoder(),channelHandler);
}
}
ClientHandler:

public class ClientPacketHandler extends SimpleChannelInboundHandler<Packet> {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        System.out.println("Channel active: " + ctx.channel().id());
        ctx.channel().writeAndFlush(new PacketSetupClientToGameServer());
        System.out.println("Sending setup packet to the GameServer: " + ctx.channel().id());
        // This is successfully called, as the client thinks the connection was properly made.
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Packet packet) {
        // Reading packets.
    }
}
公共类ClientPacketHandler扩展了SimpleChannelInboundHandler{
@凌驾
公共无效channelActive(ChannelHandlerContext ctx)引发异常{
超级通道激活(ctx);
System.out.println(“通道激活:+ctx.Channel().id());
ctx.channel();
System.out.println(“将安装包发送到游戏服务器:”+ctx.channel().id());
//这是成功调用的,因为客户端认为连接已正确建立。
}
@凌驾
受保护的无效channelRead0(ChannelHandlerContext ctx,数据包){
//阅读数据包。
}
}
我希望客户端可以正确连接到服务器。因为其他客户端正在正确连接,并且客户端以前可以正常连接


TL;DR:当多个客户端尝试创建新的匹配时,在上一个连接关闭后,可能有一个或多个客户端无法与服务器正确连接。

对于以某种方式解决此问题的一些客户端。 我做了一个变通方法,允许我继续,即使Netty框架中仍然存在一个bug(就我而言)。解决方法非常简单,只需创建一个连接池

我的解决方案在连接池中最多使用五个连接。如果其中一个连接没有得到游戏服务器的回复,那就没什么大不了的,因为还有四个连接成功的几率很高。我知道这是一个糟糕的解决方法,但我找不到关于这个问题的任何信息。它可以工作,并且只提供5秒的最大延迟(每次重试需要一秒钟)

public class ChannelInitialisation extends ChannelInitializer<SocketChannel> {
    private SimpleChannelInboundHandler<Packet> channelHandler;

    ChannelInitialisation(SimpleChannelInboundHandler<Packet> channelHandler) {
        this.channelHandler = channelHandler;
    }

    @Override
    public void initChannel(SocketChannel ch) throws Exception {
        // prefix messages by the length
        ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
        ch.pipeline().addLast(new LengthFieldPrepender(4));

        // our encoder, decoder and handler
        ch.pipeline().addLast(new PacketEncoder(), new PacketDecoder(), channelHandler);

    }
}
public class ClientPacketHandler extends SimpleChannelInboundHandler<Packet> {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        System.out.println("Channel active: " + ctx.channel().id());
        ctx.channel().writeAndFlush(new PacketSetupClientToGameServer());
        System.out.println("Sending setup packet to the GameServer: " + ctx.channel().id());
        // This is successfully called, as the client thinks the connection was properly made.
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Packet packet) {
        // Reading packets.
    }
}