Java Linux非阻塞套接字超时行为

4
我有一个Java非阻塞服务器,跟踪选择器中的所有套接字通道。然后我建立500个连接到服务器并定期发送数据。服务器收到的每个数据都会回显到客户端。
问题出现在测试良好运行几个小时后,突然间服务器正在管理的所有套接字逐渐抛出“连接超时IOException”异常,当尝试读取数据时。
我已经调查了客户端线程是否被饥饿(没有发送数据),但是我正在让迭代所有套接字并写出数据的客户端线程来执行。流量似乎一直正常地流动,但是一段时间后就全部消失了。有什么想法可能导致这种行为吗?
我在Linux平台上运行,使用最新版本的Java 6。我的应用程序启动两个线程,一个用于服务器,另一个用于所有客户端。提前感谢!
额外信息: 问题与Linux有关,而不是我的代码。当我在Windows机器上运行完全相同的设置(在相同的硬件上)时,它永远不会超时,但是在Linux上经过几个小时后开始发生。这必须是Linux中某种TCP设置引起的。感谢您的建议。

你有一些代码可以展示给我们吗? - C. K. Young
1
客户端和服务器的 netstat -a 输出呢?有没有任何处于不正常状态的套接字? - John Kugelman
你能否发布那个IOException的ex.printStackTrace()输出结果? - nos
我认为你需要像noselasd建议的那样发布代码和详细的IOException堆栈跟踪,以便解决这个问题。 - Todd Stout
3个回答

1
问题与Linux有关,而不是我的代码。当我在Windows上的相同硬件上运行完全相同的设置时,它从未超时,但在Linux上几个小时后开始出现这种情况。这一定是Linux中某种TCP设置导致的。感谢您的建议。

你看到Chris和我发表的评论了吗?我们需要更多的信息来提供帮助。 - John Kugelman
1
我已将此信息移至问题中 - 这可能不应该是答案。 - Nick Fortescue

0

所以在这两种情况下都可以工作(具有最新JVM的Windows和不具有最新JVM的Linux),服务器和客户端都在同一台机器上,使用相同的JVM?

您能澄清一下“突然逐渐”是什么意思吗?比如,几个小时后 - 总是相同数量的小时 - 然后在几秒钟内所有服务器端套接字都会抛出异常?

您没有提到客户端线程读取返回数据的情况。也许它已经停止了,而您没有注意到。(当服务器线程遇到500个快速异常时,客户端线程在做什么?尝试连续几次堆栈转储以查看。)


大约4-5小时后,Linux客户端套接字开始超时并关闭(即使它们仍在发送数据)。当它开始时,每个客户端之间有大约四分之一秒的延迟。当我在开始时连接客户端时,连接之间有250毫秒的延迟,因此似乎它们在活动相同时间后都会超时。这非常奇怪。在Windows上不会发生这种情况。 - user126368
问题存在于客户端,因为服务器接收到-1,根据我查看的文档所知,这意味着客户端已经正常关闭了套接字。服务器继续向前发展。 - user126368
我不会认为 -1/EOF 意味着干净的关闭 - 只是读取流因任何原因已经结束。你最初的报告说服务器遇到了异常;你现在是否表示它没有遇到异常?如果你想解决这个问题,请回答其他人的问题:(1)代码;(2)netstat 的输出;(3)确认客户端和服务器在两种情况下是否在同一个 JVM 中运行;(4)工作期间和立即之后的堆栈转储(SIGQUIT/Ctrl-Break)。实际的错误堆栈也会有所帮助,你应该检查单个套接字是否出现了相同的问题。 - gojomo
noselasd:不是这样的;无论是SocketChannels还是传统的InputStreams,在数据结束时都会返回-1,即使没有错误。请参见http://java.sun.com/j2se/1.5.0/docs/api/java/nio/channels/SocketChannel.html#read(java.nio.ByteBuffer)或http://java.sun.com/j2se/1.5.0/docs/api/java/io/InputStream.html#read()。 - gojomo
我认为那些链接不小心断了,以下是我认为它们应该是什么:http://java.sun.com/j2se/1.5.0/docs/api/java/nio/channels/SocketChannel.html#read%28java.nio.ByteBuffer%29 和 http://java.sun.com/j2se/1.5.0/docs/api/java/io/InputStream.html#read%28%29。 - Stobor

0
Java和JRE版本1.5或5.0中的-doCloseWithReadPending选项允许一个线程在另一个线程从同一套接字上有读取挂起时关闭套接字。
当调用close()关闭一个套接字,而该套接字有来自另一个线程的未完成读取调用时,默认情况下close()会阻塞套接字直到读取调用完成。
使用-doCloseWithReadPending选项,套接字close()调用将关闭套接字,并在具有挂起读取的线程上下文中抛出带有消息“Socket closed”的SocketException。
我不知道这是否是您问题的根本原因,但如果它影响您的问题,我想在此添加此信息。

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