写入客户端通道时出现异常 java.nio.channels.ClosedChannelException

14

我使用Netty 3.5.8创建了一个游戏服务器。

刚开始,从服务器向客户端发送数据没有任何问题。但当服务器运行一段时间后,当我尝试写入客户端通道时,会出现许多异常 [java.nio.channels.ClosedChannelException]。

有人遇到过这种异常吗?是否有什么提示可以修复它?我认为缓存缓冲区可能是原因之一。

我的代码示例如下:

ChannelBuffer bff = ChannelBuffers.buffer(18);
bff.writeByte(Events.S_SERVER_PUSH);  
bff.writeByte((byte)0);
bff.writeInt(idRoom);            
bff.writeInt(playerCnt);
bff.writeInt(gameCnt);
bff.writeInt(freePlayer);
channel.write(bff);

异常:java.nio.channels.ClosedChannelException

java.nio.channels.ClosedChannelException
        at org.jboss.netty.channel.socket.nio.AbstractNioWorker.cleanUpWriteBuffer(AbstractNioWorker.java:784)
        at org.jboss.netty.channel.socket.nio.AbstractNioWorker.writeFromUserCode(AbstractNioWorker.java:507)
        at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.handleAcceptedSocket(NioServerSocketPipelineSink.java:129)
        at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.eventSunk(NioServerSocketPipelineSink.java:66)
        at org.jboss.netty.channel.Channels.write(Channels.java:733)
        at org.jboss.netty.handler.codec.oneone.OneToOneEncoder.doEncode(OneToOneEncoder.java:71)
        at org.jboss.netty.handler.codec.oneone.OneToOneEncoder.handleDownstream(OneToOneEncoder.java:60)
        at org.jboss.netty.channel.Channels.write(Channels.java:712)
        at org.jboss.netty.channel.Channels.write(Channels.java:679)
        at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:248)
       at myclass.SendPushData(GameRoom.java:231)
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296)
        at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:458)
        at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:439)
        at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:303)
        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 java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

2
当我在for循环中写入发送数据到多个客户端时,异常更频繁地引发。 - Tuan Huy
感谢Tube。像这样编写代码: for (PlayerInfo p:this.players.values()){ ChannelBuffer bff = ChannelBuffers.buffer(18);
bff.writeByte(Events.S_SERVER_PUSH);
bff.writeByte(typePush); bff.writeInt(idRoom);
bff.writeInt(idGame); bff.writeInt(gameCnt*2); bff.writeInt(freePlayer);
p.getChannel().write(bff); Thread.sleep(100);
}
- Tuan Huy
相关问题 - https://stackoverflow.com/questions/24975455/how-do-you-detect-a-network-disconnection-when-downloading-a-file-in-java - james
3个回答

12

ClosedChannelException只是告诉您连接已关闭,因此您发出的写入请求无法完成。通常意味着:

(1) 在写入消息之前,您的应用程序在其他地方关闭了连接或
(2) 在读取您的消息之前,您的对等方关闭了连接。

如果解决了(1)和(2),则不应再看到 ClosedChannelException 的错误。


6
这句话的意思是:只是表示出现了(1)这种情况,即对等方关闭导致了一个IOException: '连接重置'。需要注意的是,在翻译过程中要保持原文意思不变,并且用通俗易懂的语言表达出来。 - user207421
您可以查看Netty的代码。channel.write()或ctx.write()会调用AbstractUnsafe的write()方法,如果出站缓冲区为空,则可能会将ClosedChannelException设置给Promise。如果对等方已关闭连接,则缓冲区可能会被清除。 - Adrian Liu
@AdrianLiu 然后Netty错误地使用了异常。它的Javadoc非常清晰。 - user207421

4
ClosedChannelException表示您已关闭通道但仍在使用它。这是您的编程错误。

1
EJP - 当连接中断时,如何确定抛出了哪个异常。我在这里尝试回答了这个问题 - https://stackoverflow.com/questions/24975455/how-do-you-detect-a-network-disconnection-when-downloading-a-file-in-java 如果您能回答这个问题并给我一些反馈,我将不胜感激。谢谢。 - james
@james,由于您已经删除了它,所以这有点困难,但至少有两个错误。ClosedChannelException和AsynchronousCloseException与对等方无关。 - user207421

1
我最近遇到了这个问题,调试起来有点麻烦。 在我的情况下,问题出在我从GUI线程创建网络连接。基本上,我只是有一个简单的按钮,在那里建立了WebSocket连接。 对我来说,这似乎很无害,因为这只是一个快速测试,以确定我的应用程序的连接能力。 我不知道的是,Android 3.0+明确禁止在GUI线程中进行任何网络操作,所以它会抛出内部异常,然后关闭连接。不幸的是,我使用的库(Jetty)没有向我传达任何信息,而且由于这是一个异步过程 - 你必须知道去哪里找。 简而言之:如果你遇到这个问题,请确保检查你是否没有从GUI线程创建连接,因为Android会关闭它们。 :D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接