2009-12-30 55 views
2

我有一個客戶端 - 服務器分層架構,客戶端向服務器發出RPC類請求。我使用Tomcat託管servlet,並使用Apache HttpClient向它發出請求。BindException:地址已在客戶端套接字上使用?

我的代碼是這樣的:

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) 

有關如何解決此問題的任何想法?我猜這是與客戶端試圖重用短暫客戶端端口有關,但爲什麼會發生這種情況/我該如何解決它? 謝謝!

回答

0

所以事實證明,問題是其中一個HttpClient實例意外地沒有使用MultiThreadedHttpConnectionManager實例化,所以我實際上沒有任何速率限制。解決這個問題解決了拋出的異常。

感謝所有的建議,但!

1

每秒連接數百個連接,不知道你的連接持續打開多久,做完他們的事情,關閉並得到回收,我懷疑這只是你將要面臨的一個問題。你可以做的一件事是在你的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(); 
+0

每個主機:2,最大:20。在世界範圍內,我能如何超過任何套接字限制與這種保守的默認值......:-p – 2009-12-30 02:42:34

0

因此,你已經發出了比TCP/IP端口允許打開更多的請求。我不做HttpClient,所以我不能詳細介紹這個,但理論上有三個解決方案針對這個特定問題:

  1. 基於硬件:添加另一個NIC(網絡接口卡)。
  2. 基於軟件:使用後直接關閉連接和/或增加連接超時。
  3. 基於平臺:增加允許打開的TCP/IP端口數量。可能是操作系統特定的和/或NIC驅動程序特定的。絕對最大值是65535,其中幾個可能已經被保留/正在使用(例如端口80)。
+0

它會不會失敗,更多的異常會導致超出上述資源?大部分資源耗盡錯誤來自socket()調用 - 聯機幫助頁面至少提到了三種不同的方式,可能由於缺乏資源而失敗,而綁定手冊頁則沒有。我期望Java異常來表明這一點。你是否仍然認爲這可能是一個問題? – 2009-12-30 02:32:23

+0

只有當HttpClient被編碼時纔會出現這樣的異常 - 我沒有看過'HttpClient#executeMethod'的代碼,但是根據你的經驗,看起來他們沒有。有理由認爲他們可能在內部發現了BindException,並在不同的客戶端端口上重新嘗試了連接,但是再一次,這會打開一整桶蠕蟲 - 它們會重試多少次?他們怎麼知道這就是你想要做的? - 它也是有道理的,他們只是拋出BindException並讓你決定。 – delfuego 2009-12-30 02:48:58

+0

通過查看跟蹤,您可以看到它直接從本機Socket連接方法拋出 – 2009-12-30 08:00:14

1

關於您遇到的問題的一個很好的討論可以找到here。在Tomcat方面,默認情況下它將使用SO_REUSEADDR選項,這將允許服務器重用處於TIME_WAIT中的套接字。另外,Apache http客戶端默認使用保持鏈接,並嘗試重新使用連接。

您的問題似乎是由於沒有在HttpClient上調用releaseConnection造成的。這是連接重複使用所必需的。否則,連接將保持打開狀態,直到垃圾收集器進入並關閉它,或者服務器斷開保持活動狀態。在這兩種情況下,它都不會返回到池中。

0

即使我們調用HttpClientUtils.closeQuietly(client);但是在你的代碼中,如果試圖從InputStream的ContentStream = HttpResponse.getEntity()。getContent()讀取HttpResponse實體的內容,那麼你應該關閉輸入流,然後只有HttpClient連接才能正常關閉。

相關問題