Apache DefaultHttpClient-java.net.BindException:地址已在使用中:connect
我正在访问Tomcat8.5Web服务器的Java“客户机”中运行性能测试。在大约13000次请求之后,HTTP请求因错误而失败Apache DefaultHttpClient-java.net.BindException:地址已在使用中:connect,java,apache-commons-httpclient,Java,Apache Commons Httpclient,我正在访问Tomcat8.5Web服务器的Java“客户机”中运行性能测试。在大约13000次请求之后,HTTP请求因错误而失败 org.apache.http.impl.client.DefaultHttpClient tryConnect INFO: Retrying connect java.net.BindException: Address already in use: connect at java.net.DualStackPlainSocketImpl.waitForC
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);
}
}
但不会改变错误。
该错误似乎不是由客户端引起的。如果我访问另一个网站的网址是好的。似乎是由于Windows中的Tomcat文件句柄或套接字资源不足或其他原因造成的。
如果我在它崩溃后作为另一个进程再次运行它,它将在1次运行(而不是13000次)中失败,因此问题是Tomcat资源不足。似乎DefaultHttpClient没有关闭其连接,或者Tomcat在gc发生之前没有释放其连接
使用HTTPClient 4.2.5
您知道为什么会发生这种情况,或者如何修复吗?似乎您使用HttpClient的方式有误(即可能是复制粘贴旧的遗留代码段)
- 首先,一个客户端(对于一个线程)就足够了李>
- 根据 最好使用池连接管理
- 您的回复应该关闭
poolighttpclientconnectionmanager cm=new-poolighttpclientconnectionmanager();
CloseableHttpClient=HttpClients.custom()
.setConnectionManager(cm)
.build();
HttpContext=HttpClientContext.create();
试一试{
最终HttpGet请求=新HttpGet(“http://localhost:9080");
对于(int i=0;i<15000;i++){
CloseableHttpResponse response=httpClient.execute(请求,上下文);
试一试{
HttpEntity=response.getEntity();
EntityUtils.consume(实体);
}最后{
response.close();
}
}
}最后{
client.close();
}
}
最佳实践是使用多线程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;
}
}
}
package com.demo.httpclient;
导入java.net.URI;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.concurrent.Callable;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
导入org.apache.http.HttpEntity;
导入org.apache.http.HttpResponse;
导入org.apache.http.client.HttpClient;
导入org.apache.http.client.methods.HttpGet;
导入org.apache.http.impl.client.DefaultHttpClient;
导入org.apache.http.impl.conn.DefaultClientConnection;
导入org.apache.http.impl.conn.poolgclientConnectionManager;
导入org.apache.http.util.EntityUtils;
公共类ThreadedHttpClientTest{
私有静态URI rootUri=URI.create(“http://localhost:8080/");
私有静态int-worker=100;
私有静态整数计数=15000;
私有静态HttpClient-HttpClient;
公共静态void main(字符串[]args)引发异常{
long startTime=System.currentTimeMillis();
PoolgClientConnectionManager PoolgClientConnectionManager=新建PoolgClientConnectionManager();
PoolgClientConnectionManager.setMaxTotal(工作者);
PoolgClientConnectionManager.setDefaultMaxPerRoute(工作者);
httpClient=新的默认httpClient(池客户端连接管理器);
List workers=new ArrayList();
for(int i=0;i
我无法重现与您相同的错误。无论如何,当我在单线程中运行您的示例时,我没有收到任何outeToHostException
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套接字
在我的OSX上,我可以更改测试的最大段生存期,错误消失了
sudo sysctl-w net.inet.tcp.msl=1000
net.inet.tcp.msl:15000->1000
DefaultHttpClient
由BasicClientConnectionManager
支持,它创建和管理单个连接,并为任何路由一次只保留一个活动连接
将连接释放回连接管理器后,它将保持活动状态以供重用,并标记为可重用
如果缓存DefaultHttpClient,则不会发生错误
这正是解决办法。我认为使用单一http客户端并允许连接管理器完成其工作是正确的
有关所有连接管理的说明,请参见
4.2.5非常古老(2013年4月)。如果你开始一个新项目,在撰写本文时更新到最新版本(4.5.12)是有意义的
参考资料:
该错误是由客户端引起的。您的本地端口已用完,因此一定存在连接泄漏。可能不在此代码中。很明显,您需要缓存客户端。它将执行连接池,但如果您继续实例化新实例,则无法执行。如果问题是客户端的端口已用完,那么为什么不在
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;
}
}
}
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)