JDK 11 HttpClient: BindException: Cannot assign requested ad



我正在使用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的情况。

我没有调用本地主机或监听本地主机端口。我正在向外部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();
}

Update:如何停止当前客户端

根据HttpClientImpl.stop方法中JDK内部私有类中的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块,你要么需要异常地使这个循环失败,要么中断正在运行的线程。

相关内容

  • 没有找到相关文章

最新更新