今天在维护一个老项目的时候发现,错误:
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; } }