6
votes

I have an Android device that communicates wirelessly with a PC, using a java.net.Socket. Everything hums along fine, but if I do nothing (i.e., no network use) for exactly 1 minute then when the Android sends a packet of data to the PC the PC receives it and sends an ACK, but the Android responds with an RST.

From Wireshark ( 10.1.2.1 is the Android, 10.1.2.11 is the PC)...

356 0.112470 10.1.2.1 10.1.2.11 TCP 97 34360→181 [PSH, ACK] Seq=1 Ack=1 Win=4935 Len=31 TSval=156103571 TSecr=320673352

359 0.000011 10.1.2.11 10.1.2.1 TCP 66 181→34360 [ACK] Seq=1 Ack=32 Win=260 Len=0 TSval=320738236 TSecr=156103571

360 0.000304 10.1.2.1 10.1.2.11 TCP 60 34360→181 [RST] Seq=32 Win=0 Len=0

At this point if I interrogate the socket's member variables it says . . .

  • isConnected = true
  • isCreated = true
  • isInputShutdown = false
  • isOutputShutdown = false
  • isClosed = false
  • isBound = true

... which looks like I should still be receiving packets just fine. So how do I figure out why I'm sending RST?

N.B. - there are no settings to "sleep" or turn off the wifi or display or any other battery-saving features set enabled on this device.

4
When I run wireshark the 2nd column is the timestamp when wireshark captured the packet, is in units of seconds and is monotonically increasing.President James K. Polk
On mine it's set for the delta since the previous captured packetuser316117

4 Answers

2
votes

The 1 minute delay looks like a timeout. It may be the SO_TIMEOUT but this does not generate network activity on itself. Also the fact that the last packet sent contains 31 bytes of data seems to indicate that the application is involved. A possible scenario would be :

  • The android application times out (on its own or triggered by a socket's SO_TIMEOUT)
  • It sends a last chunk of data, e.g. by flushing an output stream.
  • It closes abruptly the socket, for example by using the setSoLinger(true, 0) socket option.
1
votes

None of those Socket methods returns the state of the connection. They are all about the internal state of the java.net.Socket object, as determined by which constructors and methods you have called on it. They don't magically start returning false if the peer drops the connection.

You will find when you go to use the socket for I/O that you will get an IOException: 'connection reset'.

Why the connection has been reset is another matter. The usual reason is that you had sent to a connection that had already been closed by the peer, or that the peer closed the connection without reading all the data that had already arrived. In other words, an application protocol error. There are other reasons, but these are the most common.

1
votes

This could be caused by your NAT router that tries to close sockets after a timeout to free up resources. Turning on keep_alive may help. You can also try to create your own network with static IP addresses bypassing the router to rule out this hypothesis.

0
votes

When the connection is closed the isClosed() method should return TRUE. It's OK for the isConnected() method to return TRUE even if the connection has been closed because what that method tells you is "if ever you managed to get connected", the variable state is not changed/refreshed when you get disconnected.

However in your case the connection has definitely not been closed as per documentation. For more info see:

https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#isConnected--

https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#isClosed--

Note: It might help you to set to TRUE setKeepAlive(boolean)

See also:

https://docs.oracle.com/javase/8/docs/api/java/net/SocketOptions.html#SO_KEEPALIVE

https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#setKeepAlive-boolean-

Back to the problem, check for one of the following:

  1. Can you make sure for some reason there isn't another device with the same IP as the Android? Also turn off you 3G/4G and stay connected only in the wireless network.
  2. Is there a router doing NAT ? In this case the router can send the RESET flag.

If everything seems fine (it's your Android phone replying with RST) and the SO_KEEPALIVE does not work then it might be some application level error that is killing the connection.