2

OS:Linux(Debian)
Java:Java(TM)SEランタイム環境(ビルド1.7.0_05-b06)
Java:Java HotSpot(TM)64ビットサーバーVM(ビルド23.1-b03、混合モード)
Apache httpクライアント:v4。 2.3(最新)

それぞれが一意のローカルアドレス(ConnRoutePNames.LOCAL_ADDRESS)を持つ複数のクライアントで1つのPoolingConnectionManagerを作成したいと思います。
これらのクライアントは複数のワーカーによって使用されます(各ワーカーはランダムなクライアントを選択してリクエストを実行します)。

問題は次のとおりです。クライアントのローカルアドレスを設定すると、しばらくすると(たとえば、1分)、「アドレスはすでに使用されています」というメッセージとともにjava.net.BindExceptionが常に発生します。

質問:それはバグですか?

java.net.BindException: Address already in use
at java.net.PlainSocketImpl.socketBind(Native Method) ~[na:1.7.0_05]
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:376) ~[na:1.7.0_05]
at java.net.Socket.bind(Socket.java:627) ~[na:1.7.0_05]
at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:120) ~[httpclient-4.2.3.jar:4.2.3]
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180) ~[httpclient-4.2.3.jar:4.2.3]
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294) ~[httpclient-4.2.3.jar:4.2.3]
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:645) ~[httpclient-4.2.3.jar:4.2.3]
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:480) ~[httpclient-4.2.3.jar:4.2.3]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) ~[httpclient-4.2.3.jar:4.2.3]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805) ~[httpclient-4.2.3.jar:4.2.3]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784) ~[httpclient-4.2.3.jar:4.2.3]
at controllers.Test$Worker.run(Test.java:67) ~[test_2.9.1-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
at java.lang.Thread.run(Thread.java:722) [na:1.7.0_05]

コード(簡略化):

public static void main(String[] args) throws UnknownHostException
{
    ClientConnectionManager connManager = buildConnectionManager(30);

    List<HttpClient> clients = new ArrayList<>();
    for(int i=0; i<8; ++i)
    {
        HttpClient client = buildClient(connManager, InetAddress.getByName("111.111.111." + (50 + i));
        clients.add(client);
    }

    for(int i=0; i<30; ++i)
    {
        new Thread(new Worker(clients)).start();
    }
}

public static ClientConnectionManager buildConnectionManager(Integer parallelism)
{
    PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
    connectionManager.setMaxTotal(parallelism);
    connectionManager.setDefaultMaxPerRoute(parallelism);

    return connectionManager;
}

public static HttpClient buildClient(ClientConnectionManager connectionManager, InetAddress localAddress)
{
    DefaultHttpClient httpClient = new DefaultHttpClient(connectionManager);
    HttpParams params = httpClient.getParams();
    params.setParameter(ConnRoutePNames.LOCAL_ADDRESS, localAddress);

    return httpClient;
}

private static class Worker implements Runnable
{
    private List<HttpClient> clients = null;

    public Worker(List<HttpClient> clients)
    {
        this.clients = clients;
    }

    public void run()
    {

        do
        {
            HttpGet httpGet = new HttpGet("http://google.com/robots.txt");
            HttpClient client = this.clients.get(new Random().nextInt(this.clients.size()));

            try
            {
                HttpResponse httpResponse = client.execute(httpGet);
                EntityUtils.consume(httpResponse.getEntity());

                logger.debug("Success request");
            }
            catch(IOException e)
            {
                httpGet.abort();
                logger.info("IO error", e);
            }
        }
        while(true);
    }
}
4

3 に答える 3

3

この問題は、TCP スタックに関係している可能性があります。これは HttpClient のバグではないと思います。ここで解決策を見つけることができます: http://planet.jboss.org/post/concurrent_high_throughput_performance_testing_with_jmeter

于 2013-01-21T10:04:05.597 に答える
1

私が考えることができる唯一の理論は、古い接続が完全にクリーンアップされていない間に、TCP/IP スタックがポートを使い果たし、新しい接続に同じポート番号を割り当て始めるということです。この問題が HttpClient のバグであるという証拠はありません。

于 2013-01-20T19:40:39.227 に答える
0

回答ありがとうございます。
はい、問題は tcp/ip スタックにありましたが、理由がわかりませんでした :)

というわけで、以下にその理由を説明します。

接続マネージャー ( size=10 など)、複数のクライアント (それぞれ固有のローカル アドレスを持つ)、および複数のワーカーを作成しました。
各ワーカーはランダムなクライアントを受け取り、リクエストを実行します。
そのため、一度に 1 つのクライアントを最大 10 のワーカーで並行して実行することができます。
別の時間に、別のクライアントを最大 10 個のワーカーで並行して実行できます。
そのため、マネージャーの 10 個の接続すべてをキープアライブすることができず、常に閉じたり作成したりしています。

お邪魔になってすみません!

于 2013-01-21T15:49:58.470 に答える