2

I have a server setup using MINA version 2. I don't have much experience with sockets and tcp.

The problem is if I make a connection to my server, and then unplug my internet and close the connection, (Server doesn't get notification of the connection being closed) the server will forever think that my connection is still active and valid.

The server will continue to send messages to my connection, and doesn't throw any exceptions even though there is nothing on my computer binded to the local port.

How can I test that the connection still exists?

I've tried running MINA logging in debug mode, and logging the

 IoSession.isConnected() IoSession.isActive IoSession.isClosing

They always return true, true, false. Also, in debug mode, there was no useful information stating that the connection was lost. It just logged the regular "sent message" stuff, as if there was nothing wrong.

From using Flash actionscript, I have had experiences where flash will throw errors that it's operating on an invalid socket. That leads me to believe that it's saying the socket on the server is no longer valid for the connection. So in other words if flash can detect invalid sockets, a Java server should be able to detect it too correct?

If there is truly no way to detect dead connections, I can always setup a connection keep alive routine where the client is constantly sending an "I'm here" message to the server, and the server closes sessions that havent had an incoming message for a period of seconds.


EDIT: After learning that "sockets" are private and never shared over the network I managed to find better results for my issue and I found this SO thread.

Java socket API: How to tell if a connection has been closed?

Unfortunately

IOException 'Connection reset by peer' Doesn't occur when I write to the IoSession in MINA.


Edit:

Is there any way at all in Java to detect when an ACK to a TCP packet was not received after sending a packet? An ACK Timeout?


Edit:

Yet apparantly, my computer should send a RST to the server? According to this answer. https://stackoverflow.com/a/1434592/4425643 But that seems like a bad way of port scanning. Is this how port scanning works? Port scanners send data to a port and the victim's service responds with a RST? Sorry I think I need a new question for all this. But it's odd that MINA doesn't throw connection reset by peer when it sends data. So then my computer doesn't send a RST.

Community
  • 1
  • 1
  • People seem to be in agreement that the TCP ACKs are not exposed to Java in this thread. If that is the case, then I suppose it is impossible to set an ACK timeout in Java.. http://stackoverflow.com/questions/2173153/when-does-a-java-socket-send-an-ack – CausingUnderflowsEverywhere Sep 16 '16 at 04:18
  • The server should encounter a read timeout while trying to read from the client, or an `IOException: connection reset` trying to write to the client. Assuming you're using read timeouts, or the non-blocking or asynchronous equivalents, and assuming Mina isn't masking the `IOException` from you, which it shouldn't be doing. You don't have any control over ACK timeouts in Java, or any reason to think they have unusual values in your system. – user207421 Sep 16 '16 at 05:03
  • "or any reason to think they have unusual values in your system" A send waiting on an ack keeps the connection alive for over 15 minutes. Well I guess that's fine. Maybe one day I'll invent the infinite connection where the socket is saved on client side on shutdown then recovered on startup so that connection in MINA can be re-used ;) – CausingUnderflowsEverywhere Sep 16 '16 at 14:18

3 Answers3

4

The concept of socket or connection in Internet protocols is an illusion. It's a convenient abstraction that is provided to you by the operating system and the TCP stack, but in reality, it's all fake.

Under the hood, everything on the Internet takes the form of individual packets.

From the perspective of a computer sending packets to another computer, there is no built-in way to know whether that computer is actually receiving the packets, unless that computer (or some other computer in between, like a router) tells you that the packets were, or were not, received.

From the perspective of a computer expecting to receive packets from another computer, there is no way to know in advance whether any packets are coming, will ever come, or in what order -- until they actually arrive. And once they arrive, just the fact that you received one packet does not mean you'll receive any more in the future.

That's why I say connections or sockets are an illusion. The way that the operating system determines whether a connection is "alive" or not, is simply by waiting an arbitrary amount of time. After that amount of time -- called a timeout -- if one side of the TCP connection doesn't hear back from the other side, it will just assume that the other end has been disconnected, and arbitrarily set the connection status to "closed", "dead" or "terminated" ("timed out").

So:

  • Your server has no clue that you've pulled the plug on your Internet connection. It has no way of knowing that.
  • Your server's TCP stack has been configured a certain way to wait an arbitrary amount of time before "giving up" on the other end if no response is received. If this timeout is set to a very large period of time, it may appear to you that your server is hanging on to connections that are no longer valid. If this bothers you, you should look into ways to decrease the timeout interval.

Analogy: If you are on a phone call with someone, and there's a very real risk of them being hurt or killed, and you are talking to them and getting them to answer, and then the phone suddenly goes dead..... Well, how long do you wait? At what point do you assume the other person has been hurt or killed? If you wait a couple milliseconds, in most cases that's too short of a "timeout", because the other person could just be listening and thinking of how to respond. If you wait for 50 years, the person might be long dead by then. So you have to set a reasonable timeout value that makes sense.

allquixotic
  • 1,481
  • 2
  • 18
  • 37
  • Since I'm not getting the 'Connection reset by peer' exception, the timeout for TCP ACK's is probably some very large value. Thanks for the insight, I'll investigate MINA settings. – CausingUnderflowsEverywhere Sep 15 '16 at 18:37
3

What you want is a KeepAlive, heartbeat, or ping.

As per @allquicatic's answer, there's no completely reliable built-in method to do this in TCP. You'll have to implement a method to explicitly ask the client "Are you still there?" and await an answer for a specified amount of time.

https://en.wikipedia.org/wiki/Keepalive

A keepalive (KA) is a message sent by one device to another to check that the link between the two is operating, or to prevent this link from being broken.

https://en.wikipedia.org/wiki/Heartbeat_(computing)

In computer science, a heartbeat is a periodic signal generated by hardware or software to indicate normal operation or to synchronize other parts of a system.[1] Usually a heartbeat is sent between machines at a regular interval in the order of seconds. If a heartbeat isn't received for a time—usually a few heartbeat intervals—the machine that should have sent the heartbeat is assumed to have failed.[2]

The easiest way to implement one is to periodically send an arbitrary piece of data - e.g. a null command. A properly programmed TCP stack will timeout if an ACK is not received within its specified timeout period, and then you'll get a IOException 'Connection reset by peer'

You may have to manually tune the TCP parameters, or implement your own functionality if you want more fine-grained control than the default timeout.

FML Cat
  • 131
  • 4
  • I did a rough estimate, and using a heart beat would cost me about 200GB of extra bandwidth per month. I believe it's a waste of data that could've been avoided just by using a proper TCP ACK timeout. If only I could find how to set the timeout. – CausingUnderflowsEverywhere Sep 16 '16 at 04:13
  • Actually there is TCP Keep Alive that can be modified through OS kernels to set the interval and settings, According to this SO answer: http://stackoverflow.com/a/33927447/4425643 You can use it in Java, But unfortunately editing its values is not available to Java, and probably shouldn't be since you would modify system level values. Would be unfair to other programs running on the same OS. – CausingUnderflowsEverywhere Sep 16 '16 at 14:39
1

The TCP framework is not exposed to Java. And Java does not provide a means to edit TCP configuration that exists on the OS level.

This means we cannot use TCP keep alive in Java efficiently because we can't change its default configuration values. Furthermore we can't set the timeout for not receiving an ACK for a message sent. (Learn about TCP to discover that every message sent will wait for an ACK (acknowledgement) from the peer that the message has been successfully delivered.)

Java can only throw exceptions for cases such as a timeout for not completing the TCP handshake in a custom amount of time, a 'Connection Reset by Peer' exception when a RST is received from the peer, and an exception for an ACK timeout after whatever period of time that may be.

To dependably track connection status, you must implement your own Ping/Pong, Keep Alive, or Heartbeat system as @Dog suggested in his answer. (The server must poll the client to see if it's still there, or the client has to continuosly let the server know it's still there.)

For example, configure your client to send a small packet every 10 seconds. In MINA, you can set a session reader idle timeout, which will send an event when a session reader has been idle for a period of time. You can terminate that connection on delivery of this event. Setting the reader timeout to be a bit longer than the small packet interval will account for random high latency between the client and server. For example, a reader idle timeout of 15 seconds would be lenient in this case.

If your server will rarely experience session idling, and you think you can save bandwidth by polling the client when the session has gone idle, look into using the Apache MINA Keep Alive Filter.

https://mina.apache.org/mina-project/apidocs/org/apache/mina/filter/keepalive/KeepAliveFilter.html