如何在java应用程序中检测FIN-tcp标志?

时间:2012-03-26 07:45:11

标签: java sockets tcp

我在两台计算机之间建立了持久的TCP连接(第二台不在我的控制之下)。第二台计算机可以随时发送FIN标志,首先必须关闭连接(将FIN标志发送回第二台计算机)。

我如何知道第二台计算机发送FIN标志以及何时必须导致Java应用程序的socket.close()方法?

3 个答案:

答案 0 :(得分:2)

通常,您必须读取连接,当它为EOF或适当的IOException返回-1时,您可以关闭连接。注意:SocketTimeoutException并不意味着连接已关闭。

一个例子。

boolean ok = false;
try {
  int b = in.read();
  ok = b >= 0;
  if (!ok)
     throw new EOFException();
} finally {
  if (!ok)
     in.close();
}

答案 1 :(得分:1)

使用旧的Java I / O库,只能部分地检测到另一端关闭的软连接(当它们设法发送FIN / RST标志时)。您将仅通过超时了解断开连接,因此可能远非即时。你的线程可能会在他们意识到另一端的聚会早已消失之前已经挂了很长时间。

为了更好地处理它,您需要使用nio。在那里,Selector可以识别出这样的情况,即有数据准备好读取,但随后读取的信道返回小于零。这将使您几乎可以立即了解软连接重置。

另一方面,只有通过超时才能检测到硬连接终止(例如某人切断电线或网络断开),无论您使用哪个库,因为它是TCP协议本身的属性。

答案 2 :(得分:0)

如上所述,套接字的属性(isClosed,isConnected等)没有帮助。适当的解决方案是设置一个合理的SO_TIMEOUT并从套接字读取:

  • 如果套接字是封闭的,则读操作将以'-1'返回
  • 如果读取超时,则读取操作将返回,并带有读取超时异常

(标量代码)

val socket = new Socket("localhost", 8888)
socket.setSoTimeout(10000) /* Set reasonable read timeout */

try {
    val res = socket.getInputStream().read()

    if (res < 0) 
      ... /* Socket closed */
    else
      ... /* Socket read succeeded */

} catch {
    case _: SocketTimeoutException => ... /* Socket not closed */
    case _ => ... /* Merde */
}