我们遇到了一个问题,我们的客户之一,其连接在特定时间后断开连接。客户端的异常显示“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();
}
}
能否请你分享其中的代码实例化窝,在那里你关闭套接字,并在您尝试再次重新约定了吗? – Rainbolt