Android - HttpUrlConnection is not closing. Eventually results to SocketException

Viewed 6123

I am encountering some problems with the HttpUrlConnection in devices running Jellybean (4.1 - 4.3) wherein connections are not closed and results to a SocketException "Too many open files" after executing a number of times.

I do call HttpUrlConnection.disconnect() and am closing all the Inputstream, Outputstream, Reader and Writers in a finally block.

Going to adb shell and executing a netstat shows all the connections created by the application are left in CLOSE_WAIT state.

InputStream inputStream = httpUrlConnection.getInputStream();

// After calling inputStream.read() then the problem occurs. I think the 
// inputstream doesn't get closed even after calling close in a finally block. 
// The InputStream is a ChunkedInputStream if that helps.

I have tried other devices running on 2.3.3, 4.0.3 and 4.4 and did not encounter this issue.

Is there another way that I can manually close the connections?

4 Answers

I finally found a workaround. It seems that Jellybean is having an issue on "Keep-Alive" connections. I just added Connection=Close to my request header and now all is working. Doing a netstat, I see that the connections are now being closed and I no longer get the SocketException due to "Too many open files".

Check If you have tried all of the below... There might be something missing.. other wise it should not have any problem.

InputStream in;
HttpsURLConnection urlConnection =null;
try {
    URL url = new URL(Url);

    urlConnection = (HttpsURLConnection) url
                     .openConnection();
    //5 Second timeout
    urlConnection.setReadTimeout(5*1000);

    in = urlConnection.getInputStream();
    int responseCode = urlConnection.getResponseCode();

    if (responseCode != HttpURLConnection.HTTP_OK) {
         InputStream errInputStream = urlConnection.getErrorStream();
        //Print error message and response code..
         errInputStream.close();
    }
    in.close();
} catch (Exception e) {
    e.printStackTrace();
} finally{
    if(urlConnection != null)
        urlConnection.disconnect();
}

You might be better off not calling disconnect() and thus allowing it to do HTTP connection pooling.

Try using OkHttp Instead.

Once you get the Maven dependency added, you can do something like the following to download a file:

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

OutputStream output = null;

try {
  Request request   = new Request.Builder().url( download_url ).build();
  Response response = okHttpClient.newCall( request ).execute();

  if ( !response.isSuccessful() ) {
    throw new FileNotFoundException();
  }

  output = new FileOutputStream( output_path );

  output.write( response.body().bytes() );
}
finally {
  // Ensure streams are closed, even if there's an exception.
  if ( output != null ) output.flush();
  if ( output != null ) output.close();
}

Switching to OkHttp instantly fixed our leaked file descriptor issue so it's worth trying if you're stuck, even at the expense of adding another library dependency.

Related