Netty 频道随机关闭

Posted

技术标签:

【中文标题】Netty 频道随机关闭【英文标题】:Netty Channels Randomly closing 【发布时间】:2013-12-28 15:26:51 【问题描述】:

我的问题是,当多个频道连接到我的游戏时,会随机断开连接,导致所有频道都关闭。调用了 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)

【问题讨论】:

【参考方案1】:

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

【讨论】:

以上是关于Netty 频道随机关闭的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Netty 中的 ssl 握手之前优雅地关闭频道?

如何关闭写作频道

Netty - 查找频道 ID

Netty 大约 10 分钟后断开频道

NettyIO 未正确删除频道

如何使用不和谐机器人从不和谐频道随机发布文本?