2016-04-06 109 views
0

我的項目中使用的Apache HTTP客戶端發送HTTP POST請求,HTTP server.But一些奇怪的happened.I設置connectionTimeout爲10秒了socketTimeout爲10秒。對於每一天,大多數的請求時間(大約100次請求)爲100ms-200ms,但左側(大約10次請求)會拋出「連接超時」異常,這意味着連接建立時間超過10s。我不知道發生了什麼。阿帕奇的HttpClient拋出超時異常有時

我的電話是:

HttpUtils.post(HOST,空,PARAM, 「UTF-8」,10000,10000)

下面

是異常堆棧跟蹤。

org.apache.http.conn.ConnectTimeoutException: Connect to ***.***.***.***:80 [] failed: connect timed out 
    at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:134) 
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:319) 
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363) 
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219) 
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195) 
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86) 
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108) 
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) 
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) 
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106) 
    at HttpUtils.post(HttpUtils.java:201) 



    Caused by: java.net.SocketTimeoutException: connect timed out 
     at java.net.PlainSocketImpl.socketConnect(Native Method) 
     at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345) 
     at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) 
     at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) 
     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) 
     at java.net.Socket.connect(Socket.java:589) 
     at org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:72) 
     at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:125) 
     ... 84 more 

和我的HTTP POST客戶端:

import java.io.IOException; 
import java.nio.charset.Charset; 
import java.security.KeyManagementException; 
import java.security.KeyStore; 
import java.security.KeyStoreException; 
import java.security.NoSuchAlgorithmException; 
import java.security.cert.CertificateException; 
import java.security.cert.X509Certificate; 
import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 

import javax.net.ssl.SSLContext; 

import org.apache.http.Consts; 
import org.apache.http.HttpEntity; 
import org.apache.http.HttpStatus; 
import org.apache.http.NameValuePair; 
import org.apache.http.client.ClientProtocolException; 
import org.apache.http.client.config.RequestConfig; 
import org.apache.http.client.entity.UrlEncodedFormEntity; 
import org.apache.http.client.methods.CloseableHttpResponse; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.config.Registry; 
import org.apache.http.config.RegistryBuilder; 
import org.apache.http.conn.socket.ConnectionSocketFactory; 
import org.apache.http.conn.socket.LayeredConnectionSocketFactory; 
import org.apache.http.conn.socket.PlainConnectionSocketFactory; 
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; 
import org.apache.http.conn.ssl.SSLContexts; 
import org.apache.http.conn.ssl.TrustStrategy; 
import org.apache.http.impl.client.CloseableHttpClient; 
import org.apache.http.impl.client.HttpClientBuilder; 
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 
import org.apache.http.message.BasicNameValuePair; 
import org.apache.http.util.EntityUtils; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 



public class HttpUtils { 

    private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class); 
    private static int SocketTimeout = 3000;// 3秒 
    private static int ConnectTimeout = 3000;// 3秒 
    private static Boolean SetTimeOut = true; 

    public static CloseableHttpClient getHttpClient() { 

     RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory> create(); 
     ConnectionSocketFactory plainSF = new PlainConnectionSocketFactory(); 
     registryBuilder.register("http", plainSF); 
     try { 
      KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
      TrustStrategy anyTrustStrategy = new TrustStrategy() { 

       @Override 
       public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { 

        return true; 
       } 
      }; 
      SSLContext sslContext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, anyTrustStrategy).build(); 
      LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
      registryBuilder.register("https", sslSF); 
     } catch (KeyStoreException e) { 
      throw new RuntimeException(e); 
     } catch (KeyManagementException e) { 
      throw new RuntimeException(e); 
     } catch (NoSuchAlgorithmException e) { 
      throw new RuntimeException(e); 
     } 
     Registry<ConnectionSocketFactory> registry = registryBuilder.build(); 
     PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry); 
     HttpClientBuilder hcb = HttpClientBuilder.create(); 
     return hcb.setConnectionManager(connManager).build(); 
    } 

    public static String get(String url, Map<String,String> queries) throws IOException { 

     String responseBody = ""; 
     // CloseableHttpClient httpClient=HttpClients.createDefault(); 
     CloseableHttpClient httpClient = getHttpClient(); 

     StringBuilder sb = new StringBuilder(url); 

     if (queries != null && queries.keySet().size() > 0) { 
      boolean firstFlag = true; 
      Iterator<Map.Entry<String,String>> iterator = queries.entrySet().iterator(); 
      while (iterator.hasNext()) { 
       Map.Entry<String,String> entry = (Map.Entry<String,String>) iterator.next(); 
       if (firstFlag) { 
        sb.append("?" + (String) entry.getKey() + "=" + (String) entry.getValue()); 
        firstFlag = false; 
       } else { 
        sb.append("&" + (String) entry.getKey() + "=" + (String) entry.getValue()); 
       } 
      } 
     } 

     HttpGet httpGet = new HttpGet(sb.toString()); 
     if (SetTimeOut) { 
      RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SocketTimeout).setConnectTimeout(ConnectTimeout).build(); 
      httpGet.setConfig(requestConfig); 
     } 
     try { 
      CloseableHttpResponse response = httpClient.execute(httpGet); 
      int status = response.getStatusLine().getStatusCode(); 
      if (status == HttpStatus.SC_OK) { 
       HttpEntity entity = response.getEntity(); 
       // do something useful with the response body 
       // and ensure it is fully consumed 
       responseBody = EntityUtils.toString(entity); 
       // EntityUtils.consume(entity); 
      } else { 
       System.out.println("http return status error:" + status); 
       throw new ClientProtocolException("Unexpected response status: " + status); 
      } 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } finally { 
      httpClient.close(); 
     } 
     return responseBody; 
    } 

    public static String post(String url, Map<String,String> queries, Map<String,String> params, String chatset,int socketTimeout,int connectTimeout) throws IOException { 

     String responseBody = ""; 
     CloseableHttpClient httpClient = getHttpClient(); 
     StringBuilder sb = new StringBuilder(url); 

     if (queries != null && queries.keySet().size() > 0) { 
      boolean firstFlag = true; 
      Iterator<Map.Entry<String,String>> iterator = queries.entrySet().iterator(); 
      while (iterator.hasNext()) { 
       Map.Entry<String,String> entry = (Map.Entry<String,String>) iterator.next(); 
       if (firstFlag) { 
        sb.append("?" + (String) entry.getKey() + "=" + (String) entry.getValue()); 
        firstFlag = false; 
       } else { 
        sb.append("&" + (String) entry.getKey() + "=" + (String) entry.getValue()); 
       } 
      } 
     } 

     // 指定url,和http方式 
     HttpPost httpPost = new HttpPost(sb.toString()); 
     if (SetTimeOut) { 
      RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build(); 
      httpPost.setConfig(requestConfig); 
     } 
     List<NameValuePair> nvps = new ArrayList<NameValuePair>(); 
     if (params != null && params.keySet().size() > 0) { 
      Iterator<Map.Entry<String,String>> iterator = params.entrySet().iterator(); 
      while (iterator.hasNext()) { 
       Map.Entry<String,String> entry = (Map.Entry<String,String>) iterator.next(); 
       nvps.add(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue())); 
      } 
     } 
     // Consts.UTF_8 
     httpPost.setEntity(new UrlEncodedFormEntity(nvps, chatset)); 

     CloseableHttpResponse response = httpClient.execute(httpPost); 
     try { 
      if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 
       HttpEntity entity = response.getEntity(); 
       // do something useful with the response body 
       // and ensure it is fully consumed 
       responseBody = EntityUtils.toString(entity); 
       // EntityUtils.consume(entity); 
      } else { 
       System.out.println("http return status error:" + response.getStatusLine().getStatusCode()); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } finally { 
      response.close(); 
     } 
     return responseBody; 
    } 



    public static String post(String url, Map<String,String> queries, Map<String,String> params, String chatset) throws IOException { 
     return post(url, queries, params,chatset,SocketTimeout,ConnectTimeout); 
    } 


} 

從堆棧跟蹤,我們可以看到,超時連接建立過程中發生的事情,而不是數據transfer.I猜測的詳細原因在於一個其中:

1.waiting可用的連接線程池

2.cannot連接到遠程主機。

任何人都可以給我一些建議嗎?

+0

它不是池(#1),其拋出點是本機'PlainSocketImpl.socketConnect',它是實際的TCP連接。查看客戶端和服務器之間的網絡接口和路徑,和/或獲取網絡跟蹤信息,並查看SYN是否實際發生故障,是否實際到達,以及是否確認。 –

回答

0

您可以增加連接池日誌記錄位置org.apache.http.impl.conn=DEBUGhttps://hc.apache.org/httpcomponents-client-ga/logging.html因此您會看到發生異常時在池中有多少打開的連接。 異常顯示HttpClient嘗試建立新連接,這意味着打開的連接數少於池大小。

  1. 客戶端無法連接到遠程主機,因爲:

    • 網絡問題
    • 服務器關閉

    這意味着在池中沒有活動連接。然後,您需要嗅探網絡流量,找出dave_thompson_085提出的問題。

  2. 某些防火牆/防病毒功能阻止了客戶端與服務器的連接,在這種情況下池中可能存在連接。 (如果這是請求服務器的唯一過程)