簡體   English   中英

連接重置-Java(底層套接字狀態保持建立狀態)Azure VM

[英]Connection reset - Java (underlying socket status remain established) Azure VM

我正在調試連接重置的一個問題,需要一些幫助。

這是背景

使用Java版本8,Apache httpClient 4.5.2

我有一個以下程序,該程序可在Windows 10、7上成功運行,但最終在Azure Windows Server 2016 VM上重置連接。

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
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.util.EntityUtils;





public class TestConnectionReset
{
  static PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
  static  {
    connManager.setMaxTotal(10);
    connManager.setDefaultMaxPerRoute(2);
  }
  public static void main(String[] args) throws ClientProtocolException, IOException, InterruptedException {
    while (true) {
      HttpClientBuilder clientBuilder = HttpClientBuilder.create();
      RequestConfig config = RequestConfig.custom().setConnectTimeout(1800000).setConnectionRequestTimeout(1800000)
        .setSocketTimeout(1800000).build();
      clientBuilder.setDefaultRequestConfig(config);
      clientBuilder.setConnectionManager(connManager);
      String userName = "xxxxx";
      String password = "xxxxx";
      String userNamePasswordPair = String.valueOf(userName) + ":" + password;

      String authenticationData = "Basic " + new String((new Base64()).encode(userNamePasswordPair.getBytes()));

      HttpPost post = new HttpPost("https://url/rest/oauth/token");
      Map<String, String> requestBodyMap = new HashMap<String, String>();
      requestBodyMap.put("grant_type", "client_credentials");

      String req = getFormUrlEncodedBodyFromMap(requestBodyMap);

      StringEntity stringEntity = new StringEntity(req);
      post.setEntity(stringEntity);
      post.setHeader("Authorization", authenticationData);
      post.setHeader("Content-Type", "application/x-www-form-urlencoded");

      CloseableHttpClient closeableHttpClient = clientBuilder.build();
      HttpResponse response = closeableHttpClient.execute(post);
      Header[] hs = response.getAllHeaders();
      for (Header header : hs) {
        System.out.println(header.toString());
    }
      System.out.println(EntityUtils.toString(response.getEntity()));
      Thread.sleep(10*60*1000L);
    } 
  }


  public static String getFormUrlEncodedBodyFromMap(Map<String, String> formData) {
    StringBuilder requestBody = new StringBuilder();
    Iterator<Map.Entry<String, String>> itrFormData = formData.entrySet().iterator();
    while (itrFormData.hasNext()) {
      Map.Entry<?, ?> entry = (Map.Entry)itrFormData.next();
      requestBody.append(entry.getKey()).append("=").append(entry.getValue());
      if (itrFormData.hasNext()) {
        requestBody.append("&");
      }
    } 
    return requestBody.toString();
  }
}

我正在使用池httpclient連接管理器。 第一個時間循環執行中的第一個請求成功,但隨后的下一個請求for循環的后續迭代失敗。

我的發現

如果我們在Windows 10上看到底層套接字連接,則在第一個請求套接字進入CLOSE_WAIT狀態后,下一個請求將在關閉現有連接並創建新連接的情況下執行。

實際上,服務器會在5分鍾的時間內關閉連接。 但是Windows 10能夠檢測到它,並在觸發下一個請求時重新啟動連接。

現在,在Windows Server 2016上,我可以看到netstat顯示套接字已建立狀態。 意味着連接已准備就緒,可以使用該連接,並且服務器已關閉該連接,因此導致連接重置錯誤。

我懷疑它是一個環境問題,即使服務器終止后,服務器2016仍保持套接字已建立,但在Windows 10上套接字狀態已更改為CLOSE_WAIT。

對此的幫助非常感謝

終於找到了根本原因,

Microsoft Azure的問題。 他們使用SNAT並在4分鍾的空閑時間后關閉出站TCP連接。 這浪費了我5天的時間去弄清楚。

表示如果您通過保持活動狀態與服務器連接,並希望您可以重用連接,直到服務器超時並發送FIN。 但是在此之前,如果閑置時間達到4分鍾,天藍色就會殺死它。 繁榮!!。 最糟糕的是,它甚至沒有通過RST通知服務器或客戶端,這意味着違反TCP並質疑其可靠性。

 clientBuilder.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {

        @Override
        public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
            // TODO Auto-generated method stub
            return 3*60*1000;
        }
    });

使用上面的代碼,我設法在3分鍾到期時關閉連接,並在天藍色殺死它之前將其關閉。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM