Apache http客户端 - >本地地址绑定 - >一段时间后BindException

时间:2013-01-19 22:27:49

标签: java concurrency connection-pooling apache-httpclient-4.x

操作系统: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(最新版)

我想创建一个具有多个客户端的PoolingConnectionManager,每个客户端都有唯一的本地地址(ConnRoutePNames.LOCAL_ADDRESS)。
这些客户端将由几个工作人员使用(每个工作人员选择随机客户端并执行请求)。

问题是:当我为客户端设置本地地址时,经过一段时间(例如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);
    }
}

3 个答案:

答案 0 :(得分:2)

此问题可能与您的TCP堆栈有关。我不认为这是HttpClient中的错误。 您可以在这里找到解决方案: http://planet.jboss.org/post/concurrent_high_throughput_performance_testing_with_jmeter

答案 1 :(得分:0)

我能想到的唯一理论是TCP / IP堆栈用完了端口并开始为新连接分配相同的端口号,而旧连接尚未完全清除。我认为没有证据表明这个问题是HttpClient中的一个错误。

答案 2 :(得分:0)

感谢您的回答!
是的,问题出在tcp / ip stack上,但我无法理解为什么:)

所以,原因解释如下。

我创建了连接管理器(例如size = 10),几个客户端(每个客户端都有唯一的本地地址)和几个工作者。
每个工作人员随机客户端并执行请求 因此,有可能一个客户最多可以并行执行10个工作人员 在另一个时间,另一个客户可以由多达10名工人并行执行 这就是为什么,经理中的所有10个连接都无法保持,他们一直在关闭/创建。

很抱歉打扰你!