Android:HttpURLConnection没有断开连接

时间:2014-07-06 18:05:18

标签: android httpurlconnection keep-alive netstat

在服务器上运行netstat
直到几天:我只能看到连接ESTABLISHED只有大约一秒钟,然后它会从列表中消失 现在:它保持ESTABLISHED大约10秒钟,然后进入FIN_WAIT1FIN_WAIT2

Android代码是一样的,服务器仍然是相同的

某种类型的Android更新可能会改变一些事情吗?

我无法解释它。

我报告下面的代码。 urlConnection.disconnect()被执行,但连接仍在服务器上建立。

    HttpURLConnection urlConnection = null;
    System.setProperty("http.keepAlive", "false");

    try {
        URL url = new URL(stringUrl);
        urlConnection = (HttpURLConnection) url.openConnection();
        InputStream instream = new BufferedInputStream(urlConnection.getInputStream());
        ...
        instream.close();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (urlConnection!=null) {
            urlConnection.disconnect();
        }
    }

3 个答案:

答案 0 :(得分:1)

当消耗输入流上的所有数据时,连接将自动释放并添加到连接池中。假设连接将在不久的将来重用,则不会释放底层套接字连接。最好在disconnect块中调用finally,因为它会在exceptions的情况下处理连接释放。

以下是FixedLengthInputStream的读取方法的实现:

@Override public int read(byte[] buffer, int offset, int count) throws IOException {
        Arrays.checkOffsetAndCount(buffer.length, offset, count);
        checkNotClosed();
        if (bytesRemaining == 0) {
            return -1;
        }
        int read = in.read(buffer, offset, Math.min(count, bytesRemaining));
        if (read == -1) {
            unexpectedEndOfInput(); // the server didn't supply the promised content length
            throw new IOException("unexpected end of stream");
        }
        bytesRemaining -= read;
        cacheWrite(buffer, offset, read);
        if (bytesRemaining == 0) {
            endOfInput(true);
        }
        return read;
    }

当bytesRemaining变量变为0时,调用endOfInput,这将使用true参数进一步调用release方法,这将确保连接被合并。

protected final void endOfInput(boolean reuseSocket) throws IOException {
    if (cacheRequest != null) {
            cacheBody.close();
    }
    httpEngine.release(reuseSocket);
}

这是release方法实现。 最后一次检查确保是否需要关闭连接或将其添加到连接池以供重复使用。

public final void release(boolean reusable) {
    // If the response body comes from the cache, close it.
    if (responseBodyIn == cachedResponseBody) {
        IoUtils.closeQuietly(responseBodyIn);
    }
    if (!connectionReleased && connection != null) {
        connectionReleased = true;
        // We cannot reuse sockets that have incomplete output.
        if (requestBodyOut != null && !requestBodyOut.closed) {
            reusable = false;
        }
        // If the headers specify that the connection shouldn't be reused, don't reuse it.
        if (hasConnectionCloseHeader()) {
            reusable = false;
        }
        if (responseBodyIn instanceof UnknownLengthHttpInputStream) {
            reusable = false;
        }
        if (reusable && responseBodyIn != null) {
            // We must discard the response body before the connection can be reused.
            try {
                Streams.skipAll(responseBodyIn);
            } catch (IOException e) {
                reusable = false;
            }
        }
        if (!reusable) {
            connection.closeSocketAndStreams();
            connection = null;
        } else if (automaticallyReleaseConnectionToPool) {
            HttpConnectionPool.INSTANCE.recycle(connection);
            connection = null;
        }
    }
}

注意:我之前回答了几个与HttpURLConnection相关的SO问题,这些问题可以帮助您理解底层实现。以下是链接:Link1Link2

答案 1 :(得分:0)

根据TCP协议的工作原理,当您关闭连接时,它不会自动从套接字列表中消失。

将终止信号发送到另一部分时,会启动一个协议(一个程序,更像是一个程序),其中第一步恰恰是你关闭连接的意图。您将信号发送到另一个节点,这将涉及FIN_WAIT1状态。

当用户收到该信号时,下一步是从远程端确认。这意味着对方服务器向您发送另一个信号,表示该节点已准备好关闭连接。这将是FIN_WAIT2状态。

在这两个步骤之间,可能会发生远程节点尚未响应(因此您未确认要关闭连接)。在那个时候,你将处于一个名为CLOSE_WAIT的中间状态(恢复:一旦你将FIN信号发送到远程服务器并且他们还没有响应)。

TIME_WAIT状态意味着您在确定关闭它以接收一些数据包之前给服务器一些优雅的时间。这样做是因为可能发生连接异常,并且远程服务器可能没有收到“断开连接”消息并向您发送一些数据包。因此,当发生这种情况时,不是在两个节点之间创建新套接字,而是将其与TIME_WAIT状态中的套接字关联,并简单地丢弃该数据包,因为序列号可能不会被排序。

还有一些其他状态you might see,但根据你描述它的方式,对我来说似乎很正常,除非你调用.disconnect()方法时,ESTABLISHED状态会持续。在这种情况下,某些东西没有按预期工作(它可能与某种重载或非优化代码有关,这可能会使您的执行速度变慢)。

答案 2 :(得分:0)

您必须断开打开的UrlConnection

HttpURLConnection urlConnection = null;
System.setProperty("http.keepAlive", "false");

try {
    URL url = new URL(stringUrl);
    urlConnection = (HttpURLConnection) url.openConnection();
    InputStream instream = new BufferedInputStream(urlConnection.getInputStream());
    ...
    instream.close();
    urlConnection.disconnect(); //HERE
} catch (MalformedURLException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (urlConnection!=null) {
        urlConnection.disconnect();
    }
}