6

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.

user316117
  • 7,971
  • 20
  • 83
  • 158

4 Answers4

2

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.
bwt
  • 17,292
  • 1
  • 42
  • 60
1

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.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • So I have to keep **polling** in Android? But I thought the Android programming paradigm is event-driven. One of my co-workers, who maintains a program on the PC that does something similar to my app in VB using Winsock can simply register for an event and it gets called if the connection goes down. I've tested his program and it works. I posted a SO question about it: [ https://stackoverflow.com/questions/44681648/in-android-how-can-i-receive-an-event-when-my-socket-closes-or-disconnects] (link) – user316117 Jun 22 '17 at 15:45
  • I didn't say anything about polling. I said to just use the socket. `java.net.Socket` is not event-based. – user207421 Jun 24 '17 at 00:10
  • Polling is the synchronous sampling of a device or process to determine its state. So "using" the socket just to test seems like polling to me. Anyway, according to Wireshark **Android is sending the RST**, and that's the first thing that happens when the connection goes down. So how do I figure out why Android is sending an RST? – user316117 Jun 26 '17 at 16:20
  • I didn't say anything about using the socket 'just to test' either. I don't advocate that in any way shape or form. What I advocate is what I said: using the socket 'for I/O', i.e. normally, and dealing with the exceptions as they arise, rather than trying to predict the further with calls like `isConnected()`. I have already answered your final question. – user207421 Jun 30 '17 at 22:48
1

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.

Jean de Lavarene
  • 3,461
  • 1
  • 20
  • 28
0

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.

Alboz
  • 1,833
  • 20
  • 29
  • This is not a phone with access to a telco network so no worries about 3G/4G. There is no router doing NAT - this is just a PC, a WAP, and the Android device. _it might be some application level error that is killing the connection_ -- **I'm not sure what you mean**. What does it mean to "kill the connection" and what would I look for in the socket state or trace showing a "killed" connection?? (or what events could I register for if a connection is "killed"?) – user316117 Jun 24 '17 at 17:29
  • @user316117 did you set the setKeepAlive(true); ? Still the same issue? – Alboz Jun 24 '17 at 20:41
  • keepalive is not a good idea with battery-operated devices because it kills the battery. How would it be helpful for diagnosing why Android is sending an RST? – user316117 Jun 26 '17 at 16:24
  • When the *local socket* is closed `isClosed()` should return true, and at no other time, regardless of the state of the connection. You've here contradicted your own [other answer](https://stackoverflow.com/a/33699563/207421) on this topic. – user207421 Jul 16 '17 at 13:48
  • @EJP where I'm contradicting my other answer? I'm saying exactly the same. – Alboz Jul 17 '17 at 10:33
  • You said here 'when the *connection* is closed', and you said there 'when the socket is closed'. They aren't the same thing. – user207421 Jul 29 '18 at 07:24