Search code examples
javaandroidsocketswifimanageronbackpressed

Android - Socket does not close fast enough


I've got a client-app and a server-app. The client-app is sending packets to the server-app via java.net.Socket (Protocol = TCP). On Socket.Close() my server-app instantly shows me that the connection was closed - and this is how it has to work properly. Note: the whole tcp-streaming logic is in a secondary activity, that's why I am using the onBackPressed() function to finish the whole tcp-streaming and switch to the primary activity.

Working scenario:

@Override
public void onBackPressed(){
      m_socket.Close();
      finish();
}

As explained the socket gets closed and the server immediately notifies that the connection was closed.

The not working scenario, as Socket.close() seems to be too slow:

@Override
public void onBackPressed(){
      m_socket.Close();
      m_wifiManager.disconnect();
      finish();
}

This scenario does only work properly in 20% of the cases. In the other 80% my server-app notifies that the connection was closed with a big delay. In my opinion that's because of the time the tcp-socket needs for closing - so the process gets interrupted by the wifi-connection disconnect and there could not be a proper closing for the socket (#). As a proof for my opinion: This scenario works in 100% of the cases if I debug it step-by-step. The server notifies immediately.

What I've already tried and what also does not work properly:

  • m_wifiManager.disconnect() in onPause()

  • m_wifiManager.disconnect() in onDestroy()

So my questions are:

  1. Is my opinion (#) correct? Does it lack on time for the socket-closing?

  2. How do I fix this? So that tcp-socket-closing finishes properly, like in the first scenario, and after that the wifi disconnects?


Solution

  • The problem is probably with SO_LINGER socket option:

    Specify a linger-on-close timeout. This option disables/enables immediate return from a close() of a TCP Socket. Enabling this option with a non-zero Integer timeout means that a close() will block pending the transmission and acknowledgement of all data written to the peer, at which point the socket is closed gracefully. Upon reaching the linger timeout, the socket is closed forcefully, with a TCP RST. Enabling the option with a timeout of zero does a forceful close immediately. If the specified timeout value exceeds 65,535 it will be reduced to 65,535.

    It's disabled by default, your close call returns immediately and you disconnect wifi before the socket was actually closed. You need to call setSoLinger to fix it:

    m_socket.setSoLinger(true, 1);