代码之家  ›  专栏  ›  技术社区  ›  Steven Schlansker

bindException:地址已在客户端套接字上使用?

  •  2
  • Steven Schlansker  · 技术社区  · 15 年前

    我有一个客户机-服务器分层体系结构,客户机向服务器发出类似RPC的请求。我正在使用Tomcat托管servlet,并使用ApacheHTTPClient向它发出请求。

    我的代码是这样的:

        private static final HttpConnectionManager CONN_MGR = new MultiThreadedHttpConnectionManager();
        final GetMethod get = new GetMethod();
        final HttpClient httpClient = new HttpClient(CONN_MGR);
        get.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
        get.getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
    
        get.setQueryString(encodedParams);
        int responseCode;
        try {
            responseCode = httpClient.executeMethod(get);
        } catch (final IOException e) {
            ...
        }
        if (responseCode != 200)
            throw new Exception(...);
    
        String responseHTML;
        try {
            responseHTML = get.getResponseBodyAsString(100*1024*1024);
        } catch (final IOException e) {
            ...
        }
        return responseHTML;
    

    它在轻负载环境下工作得很好,但是当我每秒发出数百个请求时,我开始看到这一点。-

    Caused by: java.net.BindException: Address already in use
        at java.net.PlainSocketImpl.socketBind(Native Method)
        at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:336)
        at java.net.Socket.bind(Socket.java:588)
        at java.net.Socket.<init>(Socket.java:387)
        at java.net.Socket.<init>(Socket.java:263)
        at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:80)
        at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:122)
        at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
        at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387)
        at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
    

    有没有想过如何解决这个问题?我猜这与客户端试图重用短暂的客户端端口有关,但为什么会发生这种情况/我如何修复它? 谢谢!

    5 回复  |  直到 7 年前
        1
  •  2
  •   brianegge    15 年前

    对你遇到的问题可以进行很好的讨论。 here . 在Tomcat端,默认情况下它将使用 SO_REUSEADDR 选项,它将允许服务器重用及时等待的套接字。此外,默认情况下,ApacheHTTP客户机将使用keep alives,并尝试重用连接。

    你的问题似乎是由不打电话引起的 releaseConnection 在httpclient上。这是重新使用连接所必需的。否则,连接将保持打开状态,直到垃圾收集器来并关闭它,或者服务器断开keep-alive。在这两种情况下,它都不会返回池中。

        2
  •  1
  •   delfuego    15 年前

    由于每秒有数百个连接,而且不知道连接保持打开、执行它们的操作、关闭和回收的时间有多长,我怀疑这只是您将要遇到的一个问题。你能做的一件事就是 BindException 在try块中,使用它在bind unsuccessful情况下执行所需的任何操作,并将整个调用包装在 while 依赖于指示绑定是否成功的标志的循环。在我的头顶上:

    boolean hasBound = false;
    while (!hasBound) {
        try {
            hasBound = true;
            responseCode = httpClient.executeMethod(get);
        } catch (BindException e) {
            // do anything you want in the bound-unsuccessful case
        } catch (final IOException e) {
            ...
        }
    }
    

    更新问题: 一个奇怪的问题是:您允许的最大连接总数和每个主机的连接数是多少? MultiThreadedHttpConnectionManager ?在你的代码中,这是:

    CONN_MGR.getParams().getDefaultMaxConnectionsPerHost();
    CONN_MGR.getParams().getMaxTotalConnections();
    
        3
  •  0
  •   BalusC    15 年前

    因此,您触发的请求数超过了允许打开的TCP/IP端口数。我不做httpclient,所以我不能详细讨论这个问题,但理论上,这个特定问题有三种解决方案:

    1. 基于硬件:添加另一个NIC(网络接口卡)。
    2. 基于软件:使用后直接关闭连接和/或增加连接超时。
    3. 基于平台:增加允许打开的TCP/IP端口数量。可能是操作系统特定的和/或NIC驱动程序特定的。绝对最大值为65535,其中几个可能已被保留/使用(例如端口80)。
        4
  •  0
  •   Steven Schlansker    15 年前

    因此,问题是,另一个httpclient实例意外地没有使用我实例化的多线程dhttpConnectionManager,所以我实际上根本没有速率限制。修复此问题修复了引发的异常。

    不过,谢谢所有的建议!

        5
  •  0
  •   Ankireddy Polu    7 年前

    即使我们调用httpclientutils.closequiely(client);但是在您的代码中,如果试图从httpResponse实体(如inputstream contentstream=httpResponse.getEntity().getContent())中读取内容,则应该关闭inputstream,然后只有httpclient连接才能正确关闭。