关闭套接字的输入流需要太长时间

时间:2014-02-07 17:15:44

标签: java sockets tcp

我们偶尔遇到一个问题,我们的客户之一,在特定时间后连接断开连接。客户端的例外显示“读取超时”消息。由于我们不在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的值?在任何情况下,客户端已经中止了另一端的连接,因此,在关闭套接字之前将linger选项设置为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();
      }
    }

1 个答案:

答案 0 :(得分:0)

关闭套接字的输入流会关闭套接字和输出流,而不会刷新它。影响套接字的唯一实际操作是关闭它。关闭套接字是异步的,除非您使用SO_LINGER选项搞乱,所以通常情况下不会出现您所描述的情况。

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

解决方案:不要。

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

结论:当这些读取超时发生时,您没有关闭客户端应用程序中的套接字。

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

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

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

  1. 您是如何“完全禁用Java应用程序中的套接字超时”的?
  2. 你说你的服务器正在“清理”,但你也说它“首先没有发起关闭”。为什么不呢?