我们正在使用HttpURLConnection API来经常向同一个提供程序调用REST API(一种聚合用例) . 我们希望保持对提供者主机始终开放的5个连接池(始终是相同的IP) .
什么是正确的解决方案?这是我们尝试的:
System.setProperty("http.maxConnections", 5); // set globally only once
...
// everytime we need a connection, we use the following
HttpURLConnection conn = (HttpURLConnection) (new URL(url)).openConnection();
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(true);
...
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
...
此时我们读取输入流,直到BufferedReader不再返回字节为止 . 如果我们想要重用与提供者的底层连接,那么在那之后我们该怎么做?我们的印象是,如果完全读取输入流,则将连接添加回池中 .
它已经用这种方式工作了几个星期,但今天它停止工作产生这个例外: java.net.SocketException: Too many open files
我们在CLOSE_WAIT状态下发现了许多套接字(通过运行 lsof
): java 1814 root 97u IPv6 844702 TCP colinux:58517->123.123.254.205:www (CLOSE_WAIT)
conn.getInputStream() . close()或conn.disconnect()是否会完全关闭连接并将其从池中删除?
3 回答
来自here:
我读到这个,好像你的解决方案应该工作,但你也可以自由地调用close,连接仍然可以重用 .
我们在Java 5上也遇到了这个问题,我们的解决方案是使用池化连接管理器切换到Apache HttpClient .
Sun的HTTP URL处理程序的keepalive实现是非常错误的 . 没有维护线程来关闭空闲连接 .
keepalive的另一个更大问题是你需要删除回复 . 否则,连接也将成为孤立 . 大多数人不能正确处理错误流 . 有关如何正确读取错误响应的示例,请参阅我对此问题的回答,
HttpURLConnection.getResponseCode() returns -1 on second invocation
不被引用的reference真正有用 .
我们知道Apache HttpClient更好,但这需要另一个jar,我们可能会在applet中使用这个代码 .
不需要拨打
HttpURLConnection.connect()
. 我不确定它是否会阻止连接重用,但我们把它拿出来了 . 关闭流是安全的,但在连接上调用disconnect()
将阻止重用 . 此外,设置sun.net.http.errorstream.enableBuffering=true
有帮助 .以下是我们最终使用的内容: