java - Netty channel 随机关闭

标签 java sockets networking netty channel

我的问题是,当多个 channel 连接到我的游戏时,随机会出现断开连接,导致所有 channel 被关闭。调用了channelDisconnected方法,并且我已经完成了这次事件的堆栈跟踪打印输出,一切看起来都很正常。我的代码如下;有什么问题吗?

public final class ServerChannelHandler extends SimpleChannelHandler {

private static ChannelGroup channels;
private static ServerBootstrap bootstrap;

public static final void init() {
    new ServerChannelHandler();
}

/**
 * Gets the amount of channels that are currently connected to us
 * @return A {@code Integer} {@code Object}
 */
public static int getConnectedChannelsSize() {
    return channels == null ? 0 : channels.size();
}

/**
 * Creates a new private constructor of this class
 */
private ServerChannelHandler() {
    channels = new DefaultChannelGroup();
    bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(CoresManager.serverBossChannelExecutor, CoresManager.serverWorkerChannelExecutor, CoresManager.serverWorkersCount));
    bootstrap.getPipeline().addLast("handler", this);
    bootstrap.setOption("reuseAddress", true); // reuses adress for bind
    bootstrap.setOption("child.tcpNoDelay", true);
    bootstrap.setOption("child.TcpAckFrequency", true);
    bootstrap.setOption("child.keepAlive", true);
    bootstrap.bind(new InetSocketAddress(Constants.PORT_ID));
}

/**
 * What happens when a new channel is open and connects to us
 */
@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
    channels.add(e.getChannel());
}

/**
 * What happens when an open channel closes the connection with us
 */
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
    channels.remove(e.getChannel());
}

@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
    ctx.setAttachment(new Session(e.getChannel()));
}

@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
    Object sessionObject = ctx.getAttachment();
    if (sessionObject != null && sessionObject instanceof Session) {
        Session session = (Session) sessionObject;
        if (session.getDecoder() == null)
            return;
        if (session.getDecoder() instanceof WorldPacketsDecoder) {
            session.getWorldPackets().getPlayer().finish();
        }
    }
}

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
    if (!(e.getMessage() instanceof ChannelBuffer))
        return;
    Object sessionObject = ctx.getAttachment();
    if (sessionObject != null && sessionObject instanceof Session) {
        Session session = (Session) sessionObject;
        if (session.getDecoder() == null)
            return;
        ChannelBuffer buf = (ChannelBuffer) e.getMessage();
        buf.markReaderIndex();
        int avail = buf.readableBytes();
        if (avail < 1 || avail > Constants.RECEIVE_DATA_LIMIT) {
            return;
        }
        byte[] buffer = new byte[avail];
        buf.readBytes(buffer);
        try {
            session.getDecoder().decode(new InputStream(buffer));
        } catch (Throwable er) {
            er.printStackTrace();
        }
    }
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent ee) throws Exception {
    ee.getCause().printStackTrace();
}

/**
 * On server shutdown, all channels are closed and the external resources
 * are released from the {{@link #bootstrap}
 */
public static final void shutdown() {
    channels.close().awaitUninterruptibly();
    bootstrap.releaseExternalResources();
}

}

堆栈跟踪:

java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1364)
    at com.sallesy.game.player.Player.realFinish(Player.java:854)
    at com.sallesy.game.player.Player.finish(Player.java:848)
    at com.sallesy.game.player.Player.finish(Player.java:815)
    at com.sallesy.networking.ServerChannelHandler.channelDisconnected(ServerChannelHandler.java:71)
    at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:120)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:558)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:553)
    at org.jboss.netty.channel.Channels.fireChannelDisconnected(Channels.java:399)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.close(AbstractNioWorker.java:721)
    at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.handleAcceptedSocket(NioServerSocketPipelineSink.java:111)
    at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.eventSunk(NioServerSocketPipelineSink.java:66)
    at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendDownstream(DefaultChannelPipeline.java:774)
    at org.jboss.netty.channel.SimpleChannelHandler.closeRequested(SimpleChannelHandler.java:338)
    at org.jboss.netty.channel.SimpleChannelHandler.handleDownstream(SimpleChannelHandler.java:260)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:585)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:576)
    at org.jboss.netty.channel.Channels.close(Channels.java:820)
    at org.jboss.netty.channel.AbstractChannel.close(AbstractChannel.java:197)
    at org.jboss.netty.channel.ChannelFutureListener$1.operationComplete(ChannelFutureListener.java:41)
    at org.jboss.netty.channel.DefaultChannelFuture.notifyListener(DefaultChannelFuture.java:428)
    at org.jboss.netty.channel.DefaultChannelFuture.addListener(DefaultChannelFuture.java:145)
    at com.sallesy.networking.encoders.WorldPacketsEncoder.sendLogout(WorldPacketsEncoder.java:1179)
    at com.sallesy.game.player.Player.logout(Player.java:801)
    at com.sallesy.networking.decoders.handlers.ButtonHandler.handleButtons(ButtonHandler.java:227)
    at com.sallesy.networking.decoders.WorldPacketsDecoder.processPackets(WorldPacketsDecoder.java:1122)
    at com.sallesy.networking.decoders.WorldPacketsDecoder.decode(WorldPacketsDecoder.java:297)
    at com.sallesy.networking.ServerChannelHandler.messageReceived(ServerChannelHandler.java:100)
    at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:558)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:553)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:84)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.processSelectedKeys(AbstractNioWorker.java:471)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:332)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:35)
    at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:102)
    at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

最佳答案

确实有点猜测,但可能是保活超时。 您可以尝试使用 IdleStateHandler 来保持连接处于 Activity 状态。

关于java - Netty channel 随机关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20505883/

相关文章:

java - ActivityManager : Warning: Activity not started, 它当前的任务已被带到前面。我读过的所有相关答案都没有成果。

使用 sha256 验证的 python 套接字文件传输不起作用,但只是有时?

MySQL 5.6 - 数据库正在运行,但没有套接字文件

java - 从网络启动时列出可运行 jar 中的资源失败

networking - 我应该为我的 Minecraft 风格的游戏使用 UDP 还是 TCP?

python - 通过网络传输 Protocol Buffer 的规范方式?

java - 对 Lotus Domino xpages java 应用程序的更改不会传播到服务器

java - 将泛型类型添加到 EnumMap

java - 两个类具有相同的 API 但不同的实现是什么意思?

sockets - poll返回POLLIN时可以读取多少数据