[英]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,因此無法對此進行詳細介紹,但是從理論上講,針對此特定問題有三種解決方案:
因此事實證明,問題在於其他HttpClient實例之一意外地沒有使用我實例化的MultiThreadedHttpConnectionManager,因此我實際上根本沒有速率限制。 解決此問題的方法解決了引發異常的問題。
不過,感謝您的所有建議!
即使我們調用HttpClientUtils.closeQuietly(client); 但是在您的代碼中,如果試圖從HttpResponse實體(例如InputStream contentStream = HttpResponse.getEntity()。getContent())讀取內容,那么您還應該關閉inputstream,然后只有HttpClient連接正確關閉。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.