Apache DefaultHttpClient-java.net.BindException:地址已在使用中:connect

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

我正在访问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.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)