繁体   English   中英

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

[英]BindException: address already in use on a client socket?

我有一个客户端-服务器分层的体系结构,客户端向服务器发出类似RPC的请求。 我正在使用Tomcat托管servlet,并使用Apache HttpClient对其进行请求。

我的代码是这样的:

    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)

有关如何解决此问题的任何想法? 我猜想这与客户端尝试重用临时客户端端口有关,但是为什么会这样/我该如何解决? 谢谢!

这里可以找到有关您遇到的问题的很好的讨论。 在Tomcat端,默认情况下它将使用SO_REUSEADDR选项,该选项将允许服务器重用TIME_WAIT中的套接字。 此外,默认情况下,Apache http客户端将使用保持活动状态,并尝试重用连接。

您的问题似乎是由于未在HttpClient上调用releaseConnection引起的。 为了重新使用连接,这是必需的。 否则,连接将保持打开状态,直到垃圾收集器出现并关闭它,或者服务器断开了保持活动状态。 在这两种情况下,都不会将其退回到池中。

每秒有数百个连接,并且不知道连接保持打开状态,进行操作,关闭和回收的时间长短,我怀疑这只是您要解决的问题。 您可以做的一件事是在try块中捕获BindException ,在绑定失败的情况下使用它来做您需要做的任何事情,然后将整个调用包装在一个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();

因此,您发出的请求数量超过允许打开TCP / IP端口的数量。 我不使用HttpClient,因此无法对此进行详细介绍,但是从理论上讲,针对此特定问题有三种解决方案:

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

因此事实证明,问题在于其他HttpClient实例之一意外地没有使用我实例化的MultiThreadedHttpConnectionManager,因此我实际上根本没有速率限制。 解决此问题的方法解决了引发异常的问题。

不过,感谢您的所有建议!

即使我们调用HttpClientUtils.closeQuietly(client); 但是在您的代码中,如果试图从HttpResponse实体(例如InputStream contentStream = HttpResponse.getEntity()。getContent())读取内容,那么您还应该关闭inputstream,然后只有HttpClient连接正确关闭。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM