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.
}
}