最近接觸的sendHttpPostRequest的問題比較多,近期碰到了關於 "java.net.SocketException: Too many open files" 的問題
異常信息如下:
ERROR | 2016-01-12 03:19:36.642 | ERROR | IREAD | [Exception]exception stack info | com.huawei.bme.commons.util.debug.DebugLogImpl.doLog(DebugLogImpl.java:480) java.net.SocketException: Too many open files at java.net.Socket.createImpl(Socket.java:397) at java.net.Socket.getImpl(Socket.java:460) at java.net.Socket.bind(Socket.java:577) at sun.reflect.GeneratedMethodAccessor26.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:139) at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:125) at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707) at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.open(MultiThreadedHttpConnectionManager.java:1361) 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) at com.huawei.iread.duibaintf.duiba.sns.SNSServer.sendPostRequestWithCode(SNSServer.java:296) at com.huawei.iread.duibaintf.duiba.sns.SNSEngine.sendPostRequestWithCode(SNSEngine.java:92) at com.huawei.iread.duibaintf.duiba.duibamall.GetDuibaExchangeResultNotifyImpl.getDuibaExchangeResultNotify(GetDuibaExchangeResultNotifyImpl.java:91)
其實也就是因為 sendPostRequestWithCode 和 getDuibaExchangeResultNotify 方法調用了 HttpClient.executeMethod 引起的。
查找linux服務器中open files文件數,發現好多是下面的情況,意思是socket資源泄漏,進程使用的sock未關閉:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 27185 duiba 100u sock 0,7 0t0 92280355 can't identify protocol java 27185 duiba 101u sock 0,7 0t0 92282035 can't identify protocol java 27185 duiba 102u sock 0,7 0t0 92280901 can't identify protocol java 27185 duiba 103u sock 0,7 0t0 92282036 can't identify protocol java 27185 duiba 104u sock 0,7 0t0 92280389 can't identify protocol java 27185 duiba 105u sock 0,7 0t0 92280390 can't identify protocol java 27185 duiba 106u sock 0,7 0t0 92280391 can't identify protocol java 27185 duiba 107u sock 0,7 0t0 92280392 can't identify protocol
Java源代碼中是這樣寫的:
try{
httpMethod = new PostMethod(url) // 設置header信息,傳輸XML格式的 httpMethod.setRequestHeader(CONTENT_TYPE_NAME, CONTENT_TYPE_VALUE_XML_UTF_8); httpMethod.setRequestEntity(entity); HttpClient httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());//使用連接池技術創建 httpClient.executeMethod(httpMethod);
}catch{...}
finally{
if (null != httpMethod)
{
httpMethod.releaseConnection();//釋放資源
}
}
從上面看,最后, httpMethod.releaseConnection();//釋放資源。實際上,HttpClient建立Socket時 ,post.releaseConnection()並沒有真正關閉連接,而是將該連接提交給 MultiThreadedHttpConnectionManager,等待復用。而http的連接是等待timeout才會自動斷開的,所以,當用完系統的句柄后,自然會報Too many open files。
所以,應該添加下面的代碼進行釋放socket:
try{ httpMethod = new PostMethod(url) // 設置header信息,傳輸XML格式的
httpMethod.setRequestHeader(CONTENT_TYPE_NAME, CONTENT_TYPE_VALUE_XML_UTF_8); httpMethod.setRequestEntity(entity); //請求頭信息中添加關閉連接
httpMethod.addRequestHeader("Connection", "close"); HttpClient httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());//使用連接池技術創建
httpClient.executeMethod(httpMethod); //連發三次機制
httpClient.getParams().setBooleanParameter("http.protocol.expect-continue", false);
}catch{...} finally{ if (null != httpMethod) { httpMethod.releaseConnection();//釋放資源
} }
還有一種說法:
linux的文件打開數超過了默認的1024個文件,具體查看linux下面的文件打開最大值的命令ulimit -a,出現信息如下:
core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 69631 max locked memory (kbytes, -l) 32 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) 69631 virtual memory (kbytes, -v) unlimited file locks (-x) unlimite
其中open files (-n) 1024 默認為1024,
有說解決方法是加大文件打開的最大值,ulimit -n 8192
但是由於Httpclient引起的。當並發訪問量過大的時候,這個方法只是治標不治本的。所有還是解決Httpclient遠程請求所造成Socket沒有釋放,使用上面的方法較好。