今天在维护一个老项目的时候发现,错误:
java.net.SocketException: Too many open files at java.net.Socket.createImpl(Socket.java:460) at java.net.Socket.getImpl(Socket.java:520) at java.net.Socket.bind(Socket.java:644) at sun.security.ssl.BaseSSLSocketImpl.bind(BaseSSLSocketImpl.java:124) at sun.security.ssl.SSLSocketImpl.bind(SSLSocketImpl.java:65) at sun.security.ssl.SSLSocketImpl.<init>(SSLSocketImpl.java:468) at sun.security.ssl.SSLSocketFactoryImpl.createSocket(SSLSocketFactoryImpl.java:153) at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:82) at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:127) 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)
大致意思是,资源未释放。
代码用的是httpClient,在finally中也关比了资源
HttpClient client = new HttpClient();
try{
PostMethod postMethod = new PostMethod(url);
......
// 执行postMethod
int statusCode = client.executeMethod(postMethod);
}cache(Exception e){
}finally{
if (postMethod != null) {
postMethod.releaseConnection();
postMethod = null;
}
}
后来找度娘了解下:
HttpClient在method.releaseConnection()后并没有把链接关闭,这个方法只是将链接返回给connection manager。
所以,我的:postMethod.releaseConnection(); 并没有把链接关闭掉。
如果使用HttpClient client = new HttpClient()实例化一个HttpClient connection manager默认实现是使用SimpleHttpConnectionManager。SimpleHttpConnectionManager有个构造函数如下
/**
* The connection manager created with this constructor will try to keep the
* connection open (alive) between consecutive requests if the alwaysClose
* parameter is set to <tt>false</tt>. Otherwise the connection manager will
* always close connections upon release.
*
* @param alwaysClose if set <tt>true</tt>, the connection manager will always
* close connections upon release.
*/
public SimpleHttpConnectionManager(boolean alwaysClose) {
super();
this.alwaysClose = alwaysClose;
}
那么在finally中,就需要关闭他:
finally {
if (postMethod != null) {
postMethod.releaseConnection();
postMethod = null;
}
if (client != null) {
((SimpleHttpConnectionManager) client.getHttpConnectionManager()).shutdown();
client = null;
}
}
同时还搜索到了这个2个参数:
client = new HttpClient();
//添加关闭连接优化Too many open files异常
client.getParams().setBooleanParameter( "http.protocol.expect-continue" , false );
//请求头信息中添加关闭连接优化Too many open files异常
method.addRequestHeader("Connection", "close");
搜索了一些文档,没有发现对这两个参数细致的解释,只能不求甚解了。测试后也确实没有文件过多的异常了
大致可以这样写:
HttpClient client = new HttpClient();
//增加的
client.getParams().setBooleanParameter("http.protocol.expect-continue", false);
//超时时间
client.setTimeout(90 * 1000);
MethodResult response = null;
PostMethod postMethod = null;
try {
postMethod = new PostMethod(url);
postMethod.setRequestHeader("Content-Type", "application/json;charset=utf-8");
.......
//增加的
postMethod.addRequestHeader("Connection", "close");
// 执行postMethod
int statusCode = client.executeMethod(postMethod);
......
} catch (HttpException e) {
logger.error("发生致命的异常,可能是协议不对或者返回的内容有问题", e);
e.printStackTrace();
response.setBody("-201");
} catch (IOException e) {
logger.error("发生网络异常", e);
e.printStackTrace();
response.setBody("-200");
} finally {
if (postMethod != null) {
postMethod.releaseConnection();
postMethod = null;
}
//增加的
if (client != null) {
((SimpleHttpConnectionManager) client.getHttpConnectionManager()).shutdown();
client = null;
}
}