[英]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.