web-dev-qa-db-ja.com

Apache DefaultHttpClient-Java.net.BindException:すでに使用されているアドレス:接続

Tomcat 8.5 WebサーバーにアクセスするJava "client"でパフォーマンステストを実行しています。約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が原因のようです。クラッシュした直後に別のプロセスとして再度実行すると、13,000回ではなく1回の実行で失敗するため、Tomcatでリソースが不足していることが問題です。 DefaultHttpClientが接続を閉じていないか、GCが発生するまでTomcatが接続を解放していないようです。

HTTPClient 4.2.5の使用

なぜそれが発生するのか、またはどのように修正するのですか?

3
James

ベストプラクティスは、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;
        }
    }
}
0
Tarun Verma