JDK11 HttpClient: BindException: 无法分配请求的地址
JDK 11 HttpClient: BindException: Cannot assign requested address
我正在使用 JDK 11 附带的新 HttpClient 发出许多请求(对 Github 的 API,但我认为这无关紧要),尤其是 GET。
对于每个请求,我构建并使用一个 HttpClient,如下所示:
final ExecutorService executor = Executors.newSingleThreadExecutor();
final HttpClient client = client = HttpClient
.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(10))
.executor(executor)
.build();
try {
//send request and return parsed response;
} finally {
//manually close the specified executor because HttpClient doesn't implement Closeable,
//so I'm not sure when it will release resources.
executor.shutdownNow();
}
这似乎工作正常,除了时不时地,我收到以下异常并且在我重新启动应用程序之前请求将不再工作:
Caused by: java.net.ConnectException: Cannot assign requested address
...
Caused by: java.net.BindException: Cannot assign requested address
at java.base/sun.nio.ch.Net.connect0(Native Method) ~[na:na]
at java.base/sun.nio.ch.Net.connect(Net.java:476) ~[na:na]
at java.base/sun.nio.ch.Net.connect(Net.java:468) ~[na:na]
请注意,这不是 JVM_Bind 的情况。
我没有调用 localhost 或监听 localhost 端口。我正在向外部 API 发出 GET 请求。但是,我也检查了 etc/hosts
文件,看起来不错,127.0.0.1
映射到 localhost
.
有谁知道为什么会这样,我该如何解决?任何帮助将不胜感激。
您可以尝试对所有请求使用一个共享的 HttpClient
,因为它在内部管理连接池,并可能使同一主机的连接保持活动状态(如果支持)。在不同的 HttpClient
上执行大量请求是无效的,因为您将拥有 n
线程池和 n
连接池,其中 n
是一定数量的客户端。他们不会与主机共享底层连接。
通常,应用程序会在某种 main()
中创建 HttpClient
的单个实例,并将其作为依赖项提供给用户。
例如:
public static void main(String... args) {
final HttpClient client = client = HttpClient
.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(10))
.build();
new GithubWorker(client).start();
}
更新:如何停止当前客户端
根据 HttpClientImpl.stop
方法中 JDK 的内部私有 class 中的 JavaDocs:
// Called from the SelectorManager thread, just before exiting.
// Clears the HTTP/1.1 and HTTP/2 cache, ensuring that the connections
// that may be still lingering there are properly closed (and their
// possibly still opened SocketChannel released).
private void stop() {
// Clears HTTP/1.1 cache and close its connections
connections.stop();
// Clears HTTP/2 cache and close its connections.
client2.stop();
// shutdown the executor if needed
if (isDefaultExecutor) delegatingExecutor.shutdown();
}
此方法从 SelectorManager.showtdown
调用(SelectorManager
在 HttpClient
的构造函数中创建),其中 shutdown()
方法在 finally
块中调用SelectorManager.run()
中的繁忙循环(是的,它实现了 Thread
)。这个繁忙的循环是 while (!Thread.currentThread().isInterrupted())
。因此,要进入此 finally
块,您需要使此循环异常失败或中断 运行 线程。
我正在使用 JDK 11 附带的新 HttpClient 发出许多请求(对 Github 的 API,但我认为这无关紧要),尤其是 GET。
对于每个请求,我构建并使用一个 HttpClient,如下所示:
final ExecutorService executor = Executors.newSingleThreadExecutor();
final HttpClient client = client = HttpClient
.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(10))
.executor(executor)
.build();
try {
//send request and return parsed response;
} finally {
//manually close the specified executor because HttpClient doesn't implement Closeable,
//so I'm not sure when it will release resources.
executor.shutdownNow();
}
这似乎工作正常,除了时不时地,我收到以下异常并且在我重新启动应用程序之前请求将不再工作:
Caused by: java.net.ConnectException: Cannot assign requested address
...
Caused by: java.net.BindException: Cannot assign requested address
at java.base/sun.nio.ch.Net.connect0(Native Method) ~[na:na]
at java.base/sun.nio.ch.Net.connect(Net.java:476) ~[na:na]
at java.base/sun.nio.ch.Net.connect(Net.java:468) ~[na:na]
请注意,这不是 JVM_Bind 的情况。
我没有调用 localhost 或监听 localhost 端口。我正在向外部 API 发出 GET 请求。但是,我也检查了 etc/hosts
文件,看起来不错,127.0.0.1
映射到 localhost
.
有谁知道为什么会这样,我该如何解决?任何帮助将不胜感激。
您可以尝试对所有请求使用一个共享的 HttpClient
,因为它在内部管理连接池,并可能使同一主机的连接保持活动状态(如果支持)。在不同的 HttpClient
上执行大量请求是无效的,因为您将拥有 n
线程池和 n
连接池,其中 n
是一定数量的客户端。他们不会与主机共享底层连接。
通常,应用程序会在某种 main()
中创建 HttpClient
的单个实例,并将其作为依赖项提供给用户。
例如:
public static void main(String... args) {
final HttpClient client = client = HttpClient
.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(10))
.build();
new GithubWorker(client).start();
}
更新:如何停止当前客户端
根据 HttpClientImpl.stop
方法中 JDK 的内部私有 class 中的 JavaDocs:
// Called from the SelectorManager thread, just before exiting.
// Clears the HTTP/1.1 and HTTP/2 cache, ensuring that the connections
// that may be still lingering there are properly closed (and their
// possibly still opened SocketChannel released).
private void stop() {
// Clears HTTP/1.1 cache and close its connections
connections.stop();
// Clears HTTP/2 cache and close its connections.
client2.stop();
// shutdown the executor if needed
if (isDefaultExecutor) delegatingExecutor.shutdown();
}
此方法从 SelectorManager.showtdown
调用(SelectorManager
在 HttpClient
的构造函数中创建),其中 shutdown()
方法在 finally
块中调用SelectorManager.run()
中的繁忙循环(是的,它实现了 Thread
)。这个繁忙的循环是 while (!Thread.currentThread().isInterrupted())
。因此,要进入此 finally
块,您需要使此循环异常失败或中断 运行 线程。