[英]Webdriver: java.net.BindException: Address already in use: connect
[英]Apache DefaultHttpClient - java.net.BindException: Address already in use: connect
我在访问 Tomcat 8.5 web 服务器的 Java“客户端”中运行性能测试。 在大约 13,000 个请求 HTTP 请求失败并出现错误后,
org.apache.http.impl.client.DefaultHttpClient tryConnect
INFO: Retrying connect
java.net.BindException: Address already in use: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:127)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:643)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
代码是,
for (int i = 0; i < 15000; i++) {
try {
if (i % 1000 == 0) System.out.println("Iterations: " + Integer.toString(i));
HttpGet request = new HttpGet("http://localhost:9080");
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request, new BasicHttpContext());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Iterations: " + Integer.toString(i));
System.exit(1);
}
}
如果我缓存 DefaultHttpClient,则不会发生错误。 也试过,
request.releaseConnection();
client.getConnectionManager().shutdown();
但不会改变错误。 该错误似乎不是由客户端引起的。 如果我访问 URL 中的另一个网站,那没关系。 似乎是由 Windows 中的 Tomcat 用尽文件句柄或套接字资源或其他东西引起的。 如果我在它崩溃后立即将它作为另一个进程再次运行,它将在 1 次运行而不是 13,000 次中失败,因此问题是 Tomcat 资源不足。 似乎 DefaultHttpClient 没有关闭它的连接,或者 Tomcat 在 gc 发生之前没有释放它的连接。
使用 HTTPClient 4.2.5
有什么想法为什么会发生,或者如何解决?
我无法重现您遇到的相同错误。 无论如何,当我在单线程中运行您的示例时,我收到 NoRouteToHostException。
13:37:57.917 [main] DEBUG org.apache.http.impl.conn.BasicClientConnectionManager - Releasing connection org.apache.http.impl.conn.ManagedClientConnectionImpl@2c7ceffa
Iterations: 16329
java.net.NoRouteToHostException: Can't assign requested address (Address not available)
at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)
at java.base/java.net.Socket.connect(Socket.java:591)
at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:121)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:326)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:605)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:440)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at com.demo.DemoApplication.main(DemoApplication.java:25)
您打开连接的速度比关闭连接的速度要快 - 关闭套接字在释放它们可用于新连接之前处于 TIME_WAIT 状态。
仅出于测试目的,您可以设置tcp_tw_reuse以允许重用 TIME_WAIT sockets。
在我的 OSX 上,我可以更改测试的最大段寿命,错误消失了。
sudo sysctl -w net.inet.tcp.msl=1000 net.inet.tcp.msl: 15000 -> 1000
DefaultHttpClient
由BasicClientConnectionManager
支持,它创建和管理单个连接,并且每次只为任何路由保留一个活动连接。
当连接被释放回连接管理器时,它保持活动状态以供重用并标记为可重用。
如果我缓存 DefaultHttpClient,则不会发生错误。
这正是解决方案。 我相信使用单个 http 客户端并允许连接管理器完成其工作的正确方法。
apache 文档中解释了所有连接管理
4.2.5 已经很老了(2013 年 4 月)。 如果您开始一个新项目,那么在撰写本文时更新到最新(4.5.12)是有意义的。
参考:
似乎您以错误的方式使用 HttpClient (即可能复制粘贴旧的旧代码片段)
IE
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(cm)
.build();
HttpContext context = HttpClientContext.create();
try {
final HttpGet request = new HttpGet("http://localhost:9080");
for(int i = 0; i < 15000; i++) {
CloseableHttpResponse response = httpClient.execute(request, context);
try {
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} finally {
response.close();
}
}
} finally {
client.close();
}
}
最佳实践是使用 MultiThread HttpClient
。 下面应该工作:
package com.demo.httpclient;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.DefaultClientConnection;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.util.EntityUtils;
public class ThreadedHttpClientTest {
private static URI rootUri = URI.create("http://localhost:8080/");
private static int worker = 100;
private static int count = 15000;
private static HttpClient httpClient;
public static void main(String[] args) throws Exception {
long startTime = System.currentTimeMillis();
PoolingClientConnectionManager poolingClientConnectionManager = new PoolingClientConnectionManager();
poolingClientConnectionManager.setMaxTotal(worker);
poolingClientConnectionManager.setDefaultMaxPerRoute(worker);
httpClient = new DefaultHttpClient(poolingClientConnectionManager);
List<Callable<Void>> workers = new ArrayList<Callable<Void>>();
for (int i = 0; i < count; i++) {
workers.add(new WorkerThread(httpClient, rootUri.toString()));
}
ExecutorService pool = Executors.newFixedThreadPool(worker);
int i=0;
for (Future<Void> future : pool.invokeAll(workers)) {
future.get();
System.out.println("Response " + i++);
}
System.out.println("Time Taken :: " + (System.currentTimeMillis() - startTime) + "ms");
pool.shutdown();
}
static class WorkerThread implements Callable<Void> {
HttpClient client;
String url;
public WorkerThread(HttpClient httpClient, String url) {
this.client = httpClient;
this.url = url;
}
@Override
public Void call() throws Exception {
HttpGet get = new HttpGet(url);
HttpResponse response = client.execute(get, new DefaultClientConnection());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
return null;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.