10

I'm developing a server that hosts 3rd party devices over TCP/IP and have been experiencing sudden connection drops (the devices are connecting via cellular). I need to find a way to detect a disconnect without having to write data to the device itself.

I've looked at using the TCP keepalive functionality but Java doesn't appear to allow any adjustment of the timing of the keepalive operations.

Is there any suggested method for doing this?

My simplified socket code is as follows:

public class Test2Socket {
    public static void main(String[] args) {
        try {
            ServerSocket skt = new ServerSocket(1111);

            Socket clientSocket = skt.accept();

            clientSocket.setKeepAlive(true);

            System.out.println("Connected..");

            BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

            String inputLine;

            while((inputLine = input.readLine()) != null)
            {
                System.out.println(inputLine);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Any feedback would be greatly appreciated.

4
  • Why can't you write data to the client? The keepalive interval is usually fixed to 2 hours, so it is not usable to quickly detect dropped connections.
    – jarnbjo
    Commented Nov 5, 2013 at 10:26
  • I tried doing that. The device just threw an error at me and had something of a hissy fit. Commented Nov 7, 2013 at 10:04
  • Have a look at my case and solution stackoverflow.com/a/31741436/413032 Commented Jul 31, 2015 at 8:21
  • Spectacularly, a wrong answer is the most voted and accepted solution. It is obvious to me that detecting Socket timeout / network disconnect is the main reason TCP exists. This aspect should not be handled at application level, which is supposed to send NOPs. TCP already sends SYN/ACK packets.
    – user9016329
    Commented Jan 24, 2018 at 20:58

5 Answers 5

10

You will not get far with the built-in keep-alives of the TCP stack. That's because the keep-alive interval cannot be tuned by your application, it is set by the OS, and the defaults are rather high (hours). This is not specific to Java.

If you need to time out in a reasonable time, you have to implement some kind of keep alive in the protocol to be used. Most of the high-level protocols I have seen have some kind of NOP functionality, where you send an "Are you there?" message and the other party sends a "Yes, I'm here" reply without doing anything else.

7
  • 1
    The first part of your question is simply not true. Of course there are system calls to set the timers: setsockopt(... TCP_KEEPIDLE ...). Commented Mar 4, 2015 at 0:15
  • 1
    The proposal in the second part is dangerous and adds complexity to client and server: you mix up levels 4 and 7 here (and must sort out all things manually). TCP gives you what you want to have - why are you doing it again? There are technical solutions - even for Java. Commented Mar 4, 2015 at 0:17
  • 2
    @AndreasFlorath: I think the original poster would really love to see: a) a link to the documentation about this wonderful system call on Windows, Mac OS X, etc.; b) how to use these from Java, in a portable way. Commented Mar 4, 2015 at 10:35
  • 1
    @AndreasFlorath Socket options to set per-socket keepalive timers do not exist on all platforms, and not in Java.
    – user207421
    Commented Nov 25, 2015 at 23:39
  • @R.G.: You are missing the point. SO_KEEPALIVE is not good enough. Commented Feb 28, 2017 at 6:02
4

For an in-depth discussion of TCP Keep-Alives see my answer here.

But basically TCP Keep-Alives are likely the best method for detecting a stale connection. The main problem is that OS defaults are set at 2 hours before the connection is checked with 11 more minutes of Keep-Alive packets before the connection will actually be dropped.

Don't write your own application-layer Keep Alive protocol when TCP already has it built in. All you have to do is set the TCP time out to something more reasonable like 2-3 minutes.

Unfortunately, since TCP timeouts are managed at the OS level and not from within the JVM, it is difficult (but not impossible) to configure TCP timeouts from within your code on a per-socket basis.

0

When you call setKeepalive() on a socket the system parameters (which are tunable) are used. (Checked it under Debian 8 with openjdk7.)

Because I needed exactly the same functionality, I wrote a small library called libdontdie that can be preloaded and works with Java.

0

Set a read timeout, with setSoTimeout(), to a reasonable value, say double the expected response time, and catch the resulting SocketTimeoutException.

NB there is no such thing as "Java TCP KeepAlive".

0

author of this library here :-)

As has been stated before, unless you rely on difficult-to-configure functionality implemented directly in the TCP protocol (keep-alives), you can hardly detect breakdowns without actually sending data over a connection.

The referenced library encapsulates traditional Java Sockets, while adding easily configurable periodic connectivity checks and ACKing. (Those will stay invisible to the application programmer). As soon as a breakdown is detected, all inscribed observers will be notified. (Depending on you configuration that can be close to real-time).

The upside is that the lib is rather easy to use (and at least in my own projects works quite reliable).

The downside is, the application layer is not meant to be used for connectivity checks. So basically that lib is using things in a way they are probably not meant to.

Side note: You mentioned your clients are cellulars. While the linked library will work on android, you might have a look at Push Notification Services instead of dealing with connectivity issues yourself. That could improve e.g. battery consumption.

Not the answer you're looking for? Browse other questions tagged or ask your own question.