2014-02-07 134 views
0

我们遇到了一个问题,我们的客户之一,其连接在特定时间后断开连接。客户端的异常显示“Read Timed out”消息。由于我们在Java应用程序中没有使用套接字超时(我们使用默认值0),我们首先想到的是客户端的超时必须来自代理或路由器。他们的IT部门正在研究这个问题。关闭套接字的输入流需要很长的时间

但是,当连接中止时,我们的客户端应用程序将关闭套接字,然后建立到我们服务器的新连接。在接收到来自同一客户端的新连接后,服务器将在旧连接开始使用新连接之前启动清理操作。当服务器检测到EOS或任何其他读取异常时,或者新连接被同一客户端接受,并且旧的连接因为任何原因未被清理时(这是由于服务器故障导致此处发生的情况)检测EOS)。该清理操作实际上包括一些日志记录,清除各种路由数据结构以及最终关闭输入和输出流。那时我们已经观察到,旧套接字块的输入流关闭15分钟,时间总是相同的。正如你所能理解的,那么一切都会出错,因为新的连接开始挨饿,同样的问题从头开始重复。

现在,我想我们在服务器端的套接字遭受不确定的FIN_WAIT_2或TIME_WAIT状态,其中套接字仍然处于这些状态之一,而没有收到必要的ACK(可能它们被丢弃),这可能会移动它以CLOSED状态。尽管我们的服务器并不是首先破坏连接的服务器,但我认为它是客户端的代理或路由器,它可能已启动并使其看起来像我们的服务器关闭。我已经读过,将服务器端的SO_LINGER选项设置为0可能有助于这种情况(尽管通常不建议这样做)。仅供参考:我们迄今没有与SO_LINGER选项混淆,但我们正在考虑这样做,因为这个问题。

请您解释一下该理论是否属实?而且,为什么要让插座关闭操作需要15分钟?这超出了正常的2 * MSL(最大段寿命)持续时间,这应该是套接字等待关闭的时间。我们是否应该将SO_LINGER选项(Java中的setSoLinger方法)的值设置为高于0的值?在任何情况下,客户端已经中止了另一端的连接,因此,在关闭套接字之前将逗留选项设置为0不会导致客户端的任何其他异常或错误状态。此外,您是否有任何工具可以模拟我们环境中丢弃的数据包?

进行套接字创建和清理的代码并不特别。这里是一个片段:

Socket socket = new Socket(ipAddress, port); 
OutputStream dataOutputStream = new BufferedOutputStream(socket.getOutputStream(), 64000); 
InputStream dataInputStream = new BufferedInputStream(socket.getInputStream(), 64000); 

流关闭代码

try { 
     if (dataInputStream != null) { 
      LOGGER.info("Going to close input stream...."); 
      dataInputStream.close(); 
     } 
    } finally { 
     if (dataOutputStream != null) { 
      LOGGER.info(".closeReaderWriter()", "Going to close output stream..."); 
      dataOutputStream.close(); 
     } 
    } 
+0

能否请你分享其中的代码实例化窝,在那里你关闭套接字,并在您尝试再次重新约定了吗? – Rainbolt

回答

0

关闭套接字的输入流关闭套接字和输出流,而不必将它。影响套接字的唯一实际操作是关闭它。关闭套接字是异步的,除非你已经搞乱了SO_LINGER选项,所以通常你所描述的情况不可能出现。

结论:你已经搞砸了SO_LINGER选项。

解决方法:不要。

您说服务器在重新连接之前无法检测到客户端问题。

结论:你是不是关闭套接字在当这些阅读出现超时的客户端应用程序。

解决方案:关闭它。然后服务器将读取EOS,关闭套接字并继续其快乐的方式。

关闭套接字的输入流是不必要的。只需关闭已包装在套接字输出流中的最外层输出流/写入器,以确保它被刷新,并且可能将套接字本身放在finally块中。

其余部分提出的问题多于答案。

  1. 你是如何'完全禁用Java应用程序中的套接字超时'的?
  2. 你说你的服务器正在'清理',但你也说它'尚未开始关闭'。为什么不?
+0

嗨EJP。首先感谢您的回答。我可能一开始并不清楚。请查看我编辑的问题以获得有关问题的答案。 – ggkekas

+0

嗨EJP。我们的客户端应用程序在套接字上关闭,但是我们的服务器因任何原因失败,无法检测到EOS。这就是我们的假设是基于客户代理人的一些奇怪反应。如果代理放弃发送给我们的FIN或RST包,那么我们的服务器无法检测到这种情况。我也不认为关闭是异步操作。关闭还必须等待来自客户端的一些ACK。如果这些ACK被丢弃,那么关闭需要很长时间。关闭Java的源代码有可能长时间操作的警告。 – ggkekas

+0

您似乎声称DataInputStream.close()需要15分钟。它没有。那么是什么呢?你的问题还不清楚。 – EJP