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.

user207421
  • 289,834
  • 37
  • 266
  • 440
PeteMitchell
  • 103
  • 1
  • 1
  • 5
  • 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 Nov 05 '13 at 10:26
  • I tried doing that. The device just threw an error at me and had something of a hissy fit. – PeteMitchell Nov 07 '13 at 10:04
  • Have a look at my case and solution http://stackoverflow.com/a/31741436/413032 – Davut Gürbüz Jul 31 '15 at 08: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. –  Jan 24 '18 at 20:58

5 Answers5

8

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.

Laszlo Valko
  • 2,386
  • 18
  • 26
  • 1
    The first part of your question is simply not true. Of course there are system calls to set the timers: setsockopt(... TCP_KEEPIDLE ...). – Andreas Florath Mar 04 '15 at 00: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. – Andreas Florath Mar 04 '15 at 00: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. – Laszlo Valko Mar 04 '15 at 10:35
  • 1
    @AndreasFlorath Socket options to set per-socket keepalive timers do not exist on all platforms, and not in Java. – user207421 Nov 25 '15 at 23:39
  • @LaszloValko: here's a link to call on Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/ee470551(v=vs.85).aspx – R.G. Feb 14 '17 at 19:59
  • @R.G.: You are missing the point. SO_KEEPALIVE is not good enough. – Laszlo Valko Feb 28 '17 at 06: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.

Community
  • 1
  • 1
Cory Klein
  • 40,647
  • 27
  • 164
  • 222
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".

user207421
  • 289,834
  • 37
  • 266
  • 440
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.

Andreas Florath
  • 3,787
  • 19
  • 31
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.

m5c
  • 15
  • 5