【问题标题】:Java HttpURLConnection and poolingJava HttpURLConnection 和池化
【发布时间】:2016-05-14 12:47:33
【问题描述】:

在阅读了有关 Java HttpURLConnection 的各种文档后,我仍然对它执行哪种池以及如何处理连接感到很困惑。

比如下面的代码

URL url = new URL(someUrl);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
OutputStream os = connection.getOutputStream();
InputStream is = connection.getInputStream();

/** Write something to os and flush */
/** Read from is */

os.close();
is.close();
connection.disconnect();
  1. osis 是否需要刷新和关闭才能使底层套接字可重用?

  2. connection.disconnect() 是否会关闭底层套接字(从而使其不可重用)? keep-alive 会影响这种行为吗?

  3. 如果我使用不同的 URL 对象,但使用相同的 URL,从它们创建的 connections 是否会共享底层套接字?当 URL 的 host 部分相同,但路径不同时呢?

  4. 何时会销毁池连接?

  5. 控制池大小的系统属性是什么?

此外,如果您还可以将 Android 版本与 Java 进行比较,那就太好了。

谢谢

【问题讨论】:

    标签: java sockets tcp


    【解决方案1】:
    1. osis 是否都需要刷新和关闭才能使底层套接字可重用?

    关闭输入流就足够了。您不能刷新输入流,并且在关闭之前刷新输出流是多余的。

    1. connection.disconnect() 会关闭底层套接字(从而使其不可重用)吗?

    它“充当提示”来关闭底层连接。

    keep-alive 会影响这种行为吗?

    是的。如果不存在,则必须关闭连接。

    1. 如果我使用不同的 URL 对象,但使用相同的 URL,从它们创建的 connections 是否会共享底层套接字?

    是的。

    如果URL的主机部分相同,但路径不同?

    是的。

    1. 什么时候会销毁池连接?

    空闲超时后。

    1. 控制池大小的系统属性是什么?

    我不知道是否有,但如果有,它将在网络属性页面中定义,您可以通过 Javadoc 找到该页面。

    此外,如果您还可以将 Android 版本与 Java 进行比较,那就太好了。

    我相信 Android 根本不做池化,但是当他们切换到 OpenJDK 源时,这应该会改变。

    【讨论】:

    • 关于第一点,我做了两个测试,每个测试有 10 个请求。在第一个测试中,我使用 getContent 获得了 InputStream 并关闭了它。在第二个测试中,我还在关闭它之前阅读了整个流。每一轮第二个请求的结果都不同:当我刚刚关闭 InputStream 时,它比其他 8 个请求慢得多(第一个是 800 毫秒,第二个是 600 毫秒,其余是 140 毫秒),当我也只读取响应时首先花费了 800 秒,其余的花费了 140 毫秒。不知道为什么会这样。使用 JDK 1.8.0_51。
    • 看起来观察到的行为与 JDK 1.6 中引入的 http.KeepAlive.remainingData 有关。 docs.oracle.com/javase/6/docs/technotes/guides/net/…
    • @Constantino 当然,如果您滥用连接,则无法将其池化。这并不奇怪。要重用你没有用尽输入的一个,它必须自己做帽子,这可能会阻塞。
    • @Angelo 它主要是从 Javadoc 中推断出来的,正如我所说的,直到我提到的这一点,它并不指的是 Android。我也阅读了源代码。
    • @EJP 我猜了这么多,我的问题更多:您能否将一些指向特定文档的指针编辑到您的问题中?
    【解决方案2】:

    实际上,接受的答案根本不适用于Android:

    1. Android 忽略 http.keepAlive 和 http.maxConnections 系统属性,因为网络代码在静态初始化期间读取这些属性(即在进程/JVM 创建期间,不检查它们是否稍后更改)。见https://code.google.com/archive/p/android-developer-preview/issues/2578

    2. 此评论不正确,因为 Android 确实支持连接池(有关详细信息,请参阅下一项):

      我相信 Android 根本不做池化,但这应该 当他们切换到 OpenJDK 源时更改。

    3. OkHttp 中实现的连接池(这是 Android 的 HttpUrlConnection 类下的实现)将计数视为全局限制所有服务器(默认为 5)。这实际上是一个错误,与标准的 Java 实现不匹配。见https://github.com/square/okhttp/issues/1843

    我在尝试禁用连接池时遇到了这种情况,但发现两者都没有任何效果(也与 Android O 确认)。取而代之的是,Android/OkHttp 会始终重用之前的 http 请求留下的 5 个连接。

    【讨论】:

    • 在系统初始化期间读取系统属性与忽略它们不同。
    • @user207421 - 当您只能从应用程序代码中更改系统属性时也是如此,这发生在 它已经应用并且以后更改它没有任何效果。如果您有办法解决这个问题,请提供它。否则,您的评论毫无用处,并且会误导人们认为他们可以更改这些系统属性并使其生效。
    • 但声称它们“被 Android 忽略,因为网络代码在静态初始化期间读取这些属性”是错误的。它们根本没有“被忽略”,它们在静态初始化期间被读取,并且 Sun/Oracle JVM 的行为方式几乎与所有系统属性相同,因此它甚至不是特定于 Android 的。你在自相矛盾。
    • 痛苦地试图向 user207421 解释这一点。最后一次尝试:如果这些 http 系统属性仅通过静态初始化设置,那么任何 Android 应用程序如何能够更改它?对于非 root 的 Android,您不能。 IOW,网络代码会忽略 Android 应用程序对这些属性所做的更改,因为应用程序只能在事后 更改属性。这是运行操作系统的 JVM 的区别,您可以在其中控制其启动的系统属性(PC)与您无法控制的操作系统属性(Android)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    相关资源
    最近更新 更多