簡體   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