How to detect FIN - tcp flag in java application?

2019-07-23 10:00发布

问题:

I have long-lasting TCP connection between two computers (second not under my control). Second computer can send FIN flag at every moment, and first must close connection corrent (send FIN flag back to second computer).

How can I know that the second computer sending a FIN flag and when I must cause socket.close() method of my Java application?

回答1:

Normally, you have to read the connection and when this returns -1 for EOF or an appropriate IOException, you can close the connection. Note: SocketTimeoutException doesn't mean the connection is closed.

an example.

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


回答2:

Detecting a soft connection close by the other side (when they manage to send FIN/RST flags) is only partially possible with the old Java I/O library. You will learn of a broken connection only via a timeout, so it may be far from immediate. Your threads may hang for a long time before they realize that the party at the other end is long gone.

In order to handle it better, you need to use nio. There, such a situation will be recognized by the Selector saying there is data ready for reading but then read on the channel returning less than zero. This will allow you to learn about soft connection resets almost immediately.

On the other hand, a hard connection termination (e.g. someone cutting the wire or network being down) can only be detected via timeouts regardless of which libraries you use as it's a property of the TCP protocol itself.



回答3:

As explained above, the Socket's properties (isClosed, isConnected, etc) are not helpful. A proper solution would be to set a reasonable SO_TIMEOUT and read from the socket:

  • In case of closed socket the read operation would return with '-1'
  • In case of read timeout, the read operation would return with read-timeout exception

(Scala code)

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 */
}


标签: java sockets tcp