2

I have a Java client that is supposed to be constantly connected to some Java server and just output whatever the server sends (see excerpt below).

The problem is that if the client computer (MacOS X) goes to sleep and then wakes up again, the client hangs at in.readLine() and does not realize that the connection is broken. I added a SO_TIMEOUT to the socket so that the client would stop blocking on readLine(), and it indeed throws a SocketTimeoutException, but then happily tries to read a line from the broken connection again.

My questions are: Why doesn't the in.readLine() fail with an IOException (so that I can re-initiate the connection) and how can I make the client reconnect to the server on a awake->sleep->awake cycle on Mac OS X?

Socket socket = new Socket(...);
socket.setSoTimeout(10000);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
[...]
while (true) {
    try {
        while ((serverSays = in.readLine()) != null) {
            System.out.println("Server says: " + serverSays);
        }
    } catch (SocketTimeoutException e) {
        continue;
    }
    // An exception other than SocketTimeoutException will break the while-loop.
}
// If another exception other than SocketTimeoutException occurs,
// catch it and re-initiate the connection and start over.
J. Doe
  • 23
  • 3

2 Answers2

0

IOException means that the local host KNOWS that the remote host is no longer provide data.

SocketTimeoutException means that the remote host simply failed to provide the data in the time allocated. It never told us that the connection is officially down.

SocketTimeoutException happens when the connection was not closed gracefully. If remote host power supply dies, or someone yanks the Ethernet cable out of it, that's what you get.

In this case, while you were sleeping, the remote host must have decided to close the connection, but your host missed the notification, being asleep.

The solution would be to assume the connection is dead after certain number of timeouts.

-1

If you need to use timeout and reconnect if socket broken, try this:

Socket socket = new Socket(...);
socket.setSoTimeout(10000);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
[...]
while (true) {
    try {
        while ((serverSays = in.readLine()) != null) {
            System.out.println("Server says: " + serverSays);
        }
    } catch (SocketTimeoutException e) {
        continue;
    } catch (IOException e) {
        //reconnecting with new Socket object and new reader, because old stream closed
        socket = new Socket(...);
        socket.setSoTimeout(10000);
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }
}
  • The problem is that an `IOException` is never thrown. It just throws the `SocketTimeoutException` and then tries to read a line again, over and over. Even if I kill the server on the other side, the client still tries to read a line (without throwing `IOException`). – J. Doe Apr 12 '17 at 17:31
  • You can try to ping this connection. Try to send simple data to server. If success, then connection is alive, else close socket and execute code in my second catch block. – Vladimir Parfenov Apr 12 '17 at 17:37
  • And you can check socket.isConnected(), but i'm not sure that it helps. – Vladimir Parfenov Apr 12 '17 at 17:38