HttpClient客戶端網絡編程——高可用、高並發


  本文是HttpClient的學習博客,RestTemplate是基於HttpClient的封裝,feign可基於HttpClient進行網絡通信。

  那么作為較底層的客戶端網絡編程框架,該怎么配置使其能高可用,高並發,可支持Https協議呢?通讀本文也許你會有答案或者啟發。

  本文是Maven項目,基於Spring,在本Demo中使用了更方便的SpringBoot。

  以后隨着理解HttpClient更深入的時候會不定期更新本博客,也歡迎感興趣的博友交流和討論。

一、本文目錄

  1. 代碼實現

  2. 測試驗證

  3. 后記

二、代碼實現

1. 項目依賴

 1 <dependency>
 2             <groupId>org.springframework.boot</groupId>
 3             <artifactId>spring-boot-starter</artifactId>
 4         </dependency>
 5 
 6         <!--httpclient-->
 7         <dependency>
 8             <groupId>org.apache.httpcomponents</groupId>
 9             <artifactId>httpclient</artifactId>
10             <version>4.5.12</version>
11         </dependency>
12 
13         <!--alibaba JSON-->
14         <dependency>
15             <groupId>com.alibaba</groupId>
16             <artifactId>fastjson</artifactId>
17             <version>1.2.70</version>
18         </dependency>
19 
20         <dependency>
21             <groupId>org.springframework.boot</groupId>
22             <artifactId>spring-boot-starter-test</artifactId>
23             <scope>test</scope>
24         </dependency>
pom.xml

2. 項目結構

  

3. 項目配置

 1 #HttpClient配置
 2 httpClient:
 3   #重試次數
 4   retryCount: 3
 5   #重啟開關
 6   requestSentRetryEnabled: true
 7   #HttpClient連接池配置
 8   pool:
 9     #總連接數
10     maxTotal: 200
11     #每個路由默認連接數,某一個/每服務每次能並行接收的請求數量
12     defaultMaxPerRoute: 50
13     #Validate connections after 15 sec of inactivity  15000
14     validateAfterInactivity: 1000
15     #idle超時時間
16     idleTimeOut: 3
17     socketCfg:
18       #是否立即發送數據,設置為true會關閉Socket緩沖,默認為false
19       tcpNoDelay: true
20       #是否可以在一個進程關閉Socket后,即使它還沒有釋放端口,其它進程還可以立即重用端口
21       soReuseAddress: true
22       #接受數據的等待超時時間,單位ms
23       soTimeOut: 500
24       #關閉Socket時,要么發送完所有數據,要么等待60s后,就關閉連接,此時socket.close()是阻塞的
25       soLinger: 60
26       #開啟監視TCP連接是否有效
27       soKeepAlive: true
application.yml

4. HttpClient客戶端配置類

  通過配置連接池管理對象PoolingHttpClientConnectionManager,設置兩個重要參數maxTotal和defaultMaxPerRoute,和其它參數。本文參數配置參考官方文檔httpcomponents-client-4.5.x,文檔上面的參數更多更齊全,包括HttpConnectionFactory、DnsResolver、ConnectionConfig、RequestConfig、RequestConfig、HttpClientContext、設置代理。這些參數本文沒有配置,使用HttpClient的默認配置,感興趣想繼續深入研究的可以去學習了解。BackoffManager可以在連接池處於閑暇時進行收縮,不過網絡上資料較少,目前還沒研究出怎么使用和配置。

  1 package com.example.httpclientdemo.common.config.http.client;
  2 
  3 import org.apache.http.config.Registry;
  4 import org.apache.http.config.RegistryBuilder;
  5 import org.apache.http.config.SocketConfig;
  6 import org.apache.http.conn.socket.ConnectionSocketFactory;
  7 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
  8 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
  9 import org.apache.http.impl.client.*;
 10 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 11 import org.apache.http.ssl.SSLContexts;
 12 import org.springframework.beans.factory.annotation.Value;
 13 import org.springframework.context.annotation.Bean;
 14 import org.springframework.context.annotation.Configuration;
 15 
 16 import java.util.concurrent.TimeUnit;
 17 
 18 /**
 19  * HttpClient客戶端配置類
 20  *
 21  * @author 復姓江山
 22  * @date 2021/02/08
 23  */
 24 @Configuration
 25 public class HttpClientConfig {
 26 
 27     /**
 28      * closeableHttpClient連接對象,支持HTTPS使用SSL套接層
 29      *
 30      * @param httpClientPoolManager   HttpClient連接池管理對象
 31      * @param retryCount              重試次數
 32      * @param requestSentRetryEnabled 重啟開關
 33      * @return closeableHttpClient連接對象
 34      */
 35     @Bean
 36     public CloseableHttpClient closeableHttpClient(final PoolingHttpClientConnectionManager httpClientPoolManager,
 37                                                    @Value("${httpClient.retryCount}") final int retryCount,
 38                                                    @Value("${httpClient.requestSentRetryEnabled}") final
 39                                                    boolean requestSentRetryEnabled) {
 40 
 41         return HttpClients.custom()
 42                 .setDefaultCookieStore(new BasicCookieStore())
 43                 .setDefaultCredentialsProvider(new BasicCredentialsProvider())
 44                 .setConnectionManager(httpClientPoolManager)
 45                 .setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, requestSentRetryEnabled))
 46                 .build();
 47     }
 48 
 49     /**
 50      * 默認socket configuration
 51      *
 52      * @param tcpNoDelay     是否立即發送數據,設置為true會關閉Socket緩沖,默認為false
 53      * @param soReuseAddress 是否可以在一個進程關閉Socket后,即使它還沒有釋放端口,其它進程還可以立即重用端口
 54      * @param soTimeOut      接受數據的等待超時時間,單位ms
 55      * @param soLinger       關閉Socket時,要么發送完所有數據,要么等待60s后,就關閉連接,此時socket.close()是阻塞的
 56      * @param soKeepAlive    開啟監視TCP連接是否有效
 57      * @return 默認socket configuration
 58      */
 59     @Bean
 60     public SocketConfig defaultSocketConfig(@Value("${httpClient.pool.socketCfg.tcpNoDelay}") final boolean tcpNoDelay,
 61                                             @Value("${httpClient.pool.socketCfg.soReuseAddress}") final boolean soReuseAddress,
 62                                             @Value("${httpClient.pool.socketCfg.soTimeOut}") final int soTimeOut,
 63                                             @Value("${httpClient.pool.socketCfg.soLinger}") final int soLinger,
 64                                             @Value("${httpClient.pool.socketCfg.soKeepAlive}") final boolean soKeepAlive) {
 65         return SocketConfig.custom()
 66                 .setTcpNoDelay(tcpNoDelay)
 67                 .setSoReuseAddress(soReuseAddress)
 68                 .setSoTimeout(soTimeOut)
 69                 .setSoLinger(soLinger)
 70                 .setSoKeepAlive(soKeepAlive).build();
 71     }
 72 
 73     /**
 74      * HttpClient連接池管理對象
 75      *
 76      * @param maxTotal                總連接數
 77      * @param defaultMaxPerRoute      每個路由默認連接數,某一個/每服務每次能並行接收的請求數量
 78      * @param validateAfterInactivity 一次連接保留時長,單位s
 79      * @param idleTimeOut             idle超時時間
 80      * @param defaultSocketConfig     默認socket configuration
 81      * @return HttpClient連接池管理對象
 82      */
 83     @Bean
 84     public PoolingHttpClientConnectionManager httpClientPoolManager(
 85             @Value("${httpClient.pool.maxTotal}") final int maxTotal,
 86             @Value("${httpClient.pool.defaultMaxPerRoute}") final int defaultMaxPerRoute,
 87             @Value("${httpClient.pool.validateAfterInactivity}") final int validateAfterInactivity,
 88             @Value("${httpClient.pool.validateAfterInactivity}") final long idleTimeOut,
 89             final SocketConfig defaultSocketConfig) {
 90         Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
 91                 .register("http", PlainConnectionSocketFactory.INSTANCE)
 92                 .register("https", new SSLConnectionSocketFactory(SSLContexts.createSystemDefault()))
 93                 .build();
 94         PoolingHttpClientConnectionManager poolManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
 95         poolManager.setMaxTotal(maxTotal);
 96         poolManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
 97         poolManager.setValidateAfterInactivity(validateAfterInactivity);
 98         poolManager.closeIdleConnections(idleTimeOut, TimeUnit.SECONDS);
 99         poolManager.setDefaultSocketConfig(defaultSocketConfig);
100         return poolManager;
101     }
102 
103 }
HttpClientConfig.java

5. HttpClient工具類

  1 package com.example.httpclientdemo.common.utils.http.client;
  2 
  3 import org.apache.http.HttpEntity;
  4 import org.apache.http.client.methods.*;
  5 import org.apache.http.impl.client.CloseableHttpClient;
  6 import org.apache.http.impl.execchain.RequestAbortedException;
  7 
  8 import java.io.*;
  9 import java.util.stream.Collectors;
 10 
 11 /**
 12  * HttpClient工具類
 13  *
 14  * @author 復姓江山
 15  * @date 2021/02/08
 16  */
 17 public final class HttpClientUtils {
 18 
 19     /**
 20      * header的Content-Type鍵
 21      */
 22     public final static String HEADER_CONTENT_TYPE = "Content-Type";
 23 
 24     /**
 25      * R3C默認Content_Type
 26      */
 27     public final static String R3C_DEFAULT_CONTENT_TYPE = "application/vnd.api+json";
 28 
 29     /**
 30      * Authorization
 31      */
 32     public final static String HEADER_AUTHORIZATION = "Authorization";
 33 
 34     private HttpClientUtils() {
 35 
 36     }
 37 
 38     /**
 39      * httpClient的響應實體
 40      *
 41      * @param httpClient httpClient對象
 42      * @param request    請求對象
 43      * @return 響應實體
 44      * @throws IOException IO異常
 45      */
 46     private static CloseableHttpResponse httpResponse(CloseableHttpClient httpClient,
 47                                                       HttpUriRequest request) throws IOException {
 48         return httpClient.execute(request);
 49     }
 50 
 51     /**
 52      * get請求
 53      *
 54      * @param httpClient httpClient對象
 55      * @param request    請求對象
 56      * @return 響應實體
 57      * @throws IOException IO異常
 58      */
 59     public static CloseableHttpResponse get(CloseableHttpClient httpClient, HttpUriRequest request) throws IOException {
 60         assert HttpGet.METHOD_NAME.equals(request.getMethod());
 61         return HttpClientUtils.httpResponse(httpClient, request);
 62     }
 63 
 64     /**
 65      * post請求
 66      *
 67      * @param httpClient httpClient對象
 68      * @param request    請求對象
 69      * @return 響應實體
 70      * @throws IOException IO異常
 71      */
 72     public static CloseableHttpResponse post(CloseableHttpClient httpClient, HttpUriRequest request) throws IOException {
 73         assert HttpPost.METHOD_NAME.equals(request.getMethod());
 74         return HttpClientUtils.httpResponse(httpClient, request);
 75     }
 76 
 77     /**
 78      * post或patch請求
 79      *
 80      * @param httpClient httpClient對象
 81      * @param request    請求對象
 82      * @return 響應實體
 83      * @throws IOException IO異常
 84      */
 85     public static CloseableHttpResponse postOrPatch(CloseableHttpClient httpClient, HttpUriRequest request) throws IOException {
 86         if (request instanceof HttpPost) {
 87             assert HttpPost.METHOD_NAME.equals(request.getMethod());
 88         } else if (request instanceof HttpPatch) {
 89             assert HttpPatch.METHOD_NAME.equals(request.getMethod());
 90         } else {
 91             throw new RequestAbortedException("Not post or patch.");
 92         }
 93         return HttpClientUtils.httpResponse(httpClient, request);
 94     }
 95 
 96     /**
 97      * patch請求
 98      *
 99      * @param httpClient httpClient對象
100      * @param request    請求對象
101      * @return 響應實體
102      * @throws IOException IO異常
103      */
104     public static CloseableHttpResponse patch(CloseableHttpClient httpClient, HttpUriRequest request) throws IOException {
105         assert HttpPatch.METHOD_NAME.equals(request.getMethod());
106         return HttpClientUtils.httpResponse(httpClient, request);
107     }
108 
109     /**
110      * httpClient的HttpEntity
111      *
112      * @param response 響應實體
113      * @return HttpEntity
114      */
115     public static HttpEntity httpEntity(final CloseableHttpResponse response) {
116         return response.getEntity();
117     }
118 
119 
120     /**
121      * 返回狀態行代碼
122      *
123      * @param response 響應實體
124      * @return 狀態行代碼
125      */
126     public static int getStatusCode(final CloseableHttpResponse response) {
127         return response.getStatusLine().getStatusCode();
128     }
129 
130     /**
131      * 獲取ContentType
132      *
133      * @param httpEntity HttpEntity
134      * @return ContentType
135      */
136     public static String getContentType(final HttpEntity httpEntity) {
137         return httpEntity.getContentType().getValue();
138     }
139 
140     /**
141      * 獲取ContentEncoding
142      *
143      * @param httpEntity HttpEntity
144      * @return ContentEncoding
145      */
146     public static String getContentEncoding(final HttpEntity httpEntity) {
147         return httpEntity.getContentEncoding().getValue();
148     }
149 
150     /**
151      * 獲取響應體對象InputStream
152      *
153      * @param httpEntity HttpEntity
154      * @return 獲取響應體對象InputStream
155      * @throws IOException IO異常
156      */
157     public static InputStream getContent(final HttpEntity httpEntity) throws IOException {
158         return httpEntity.getContent();
159     }
160 
161     /**
162      * 獲取響應體對象的字符串
163      *
164      * @param inputStream InputStream
165      * @return 獲取響應體對象InputStream
166      * @throws IOException IO異常
167      */
168     public static String getContentString(final InputStream inputStream) throws IOException {
169         return new BufferedReader(new InputStreamReader(inputStream))
170                 .lines().parallel().collect(Collectors.joining(System.lineSeparator()));
171     }
172 
173     /**
174      * 獲取響應體對象的字符串
175      *
176      * @param httpEntity HttpEntity
177      * @return 獲取響應體對象InputStream
178      * @throws IOException IO異常
179      */
180     public static String getContentString(final HttpEntity httpEntity) throws IOException {
181         return new BufferedReader(new InputStreamReader(HttpClientUtils.getContent(httpEntity)))
182                 .lines().parallel().collect(Collectors.joining(System.lineSeparator()));
183     }
184 
185     /**
186      * 字符串轉InputStream
187      *
188      * @param str 字符串
189      * @return inputStream
190      */
191     public static InputStream stringTransferToInputStream(String str) {
192         return new ByteArrayInputStream(str.getBytes());
193     }
194 
195     /**
196      * 設置默認的Content-Type
197      *
198      * @param request http請求對象
199      */
200     public static void setDefaultContentType(HttpUriRequest request) {
201         request.setHeader(HttpClientUtils.HEADER_CONTENT_TYPE, HttpClientUtils.R3C_DEFAULT_CONTENT_TYPE);
202     }
203 
204     /**
205      * 設置Authorization
206      *
207      * @param request http請求對象
208      * @param token   token
209      */
210     public static void setAuthorization(HttpUriRequest request, String token) {
211         request.setHeader(HttpClientUtils.HEADER_AUTHORIZATION, token);
212     }
213 
214     /**
215      * 設置默認請求頭
216      *
217      * @param request http請求對象
218      * @param token   token
219      */
220     public static void setDefaultHeader(HttpUriRequest request, String token) {
221         HttpClientUtils.setDefaultContentType(request);
222         HttpClientUtils.setAuthorization(request, token);
223     }
224 
225     /**
226      * 關閉連接
227      *
228      * @param response    response響應對象
229      * @param inputStream inputStream
230      */
231     public static void close(CloseableHttpResponse response, InputStream inputStream) throws IOException {
232         if (inputStream != null) {
233             inputStream.close();
234         }
235         if (response != null) {
236             response.close();
237         }
238     }
239 
240 
241 }
HttpClientUtils.java

6. HttpClient業務接口及其實現

 1 package com.example.httpclientdemo.biz.service;
 2 
 3 /**
 4  * HttpClient業務接口類
 5  *
 6  * @author 復姓江山
 7  * @date 2021/02/08
 8  */
 9 public interface HttpClientService {
10     /**
11      * get請求
12      *
13      * @param url 請求地址
14      */
15     void requestGet(String url);
16 
17     /**
18      * post請求
19      *
20      * @param url 請求地址
21      * @param obj 請求對象
22      */
23     void requestPost(String url, Object obj);
24 }
HttpClientService.java

 

 1 package com.example.httpclientdemo.biz.service.impl;
 2 
 3 import com.example.httpclientdemo.biz.provider.HttpClientProvider;
 4 import com.example.httpclientdemo.biz.service.HttpClientService;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.stereotype.Service;
 7 
 8 /**
 9  * HttpClient業務接口實現類
10  *
11  * @author 復姓江山
12  * @date 2021/02/08
13  */
14 @Service
15 public class HttpClientServiceImpl implements HttpClientService {
16 
17     @Autowired
18     private HttpClientProvider httpClientProvider;
19 
20 
21     @Override
22     public void requestGet(String url) {
23         httpClientProvider.requestGet(url);
24     }
25 
26     @Override
27     public void requestPost(String url, Object obj) {
28         httpClientProvider.requestPost(url, obj);
29     }
30 }
HttpClientServiceImpl.java

7. HttpClient業務支撐接口及其實現

  為什么會加個業務支撐接口呢?常見的分層結構或分層架構(控制層、業務層和數據訪問層——分層結構,或表示層(UI)、業務邏輯層(BLL)和數據訪問層——分層架構),在此基礎上增加provder是因為多層封裝與隔離,HttpClient是作為客戶端請求其它系統服務,請求參數與相應參數及異常處理應與本項目進行一定隔離,如果把HttpClient客戶端深度耦合到業務層中,到對方服務器變動時,就會影響本系統的核心業務邏輯。而增加了封裝與隔離后,影響的只是provider層,系統本身的核心業務邏輯不會受到深層次的影響。在這我就稍微發散一下思維,比如定義一個MQ的接口,在使用的是Kafka,RabitMQ,ActiveMQ或者RocketMQ,不管怎么變更MQ,系統業務代碼依賴的是MQ的接口,絲毫不會受到影響。所以編程原則里有一條:面向接口編程,面向抽象編程。

 1 package com.example.httpclientdemo.biz.provider;
 2 
 3 /**
 4  * HttpClient業務支撐接口類
 5  *
 6  * @author 復姓江山
 7  * @date 2021/02/08
 8  */
 9 public interface HttpClientProvider {
10 
11     /**
12      * get請求
13      *
14      * @param url 請求地址
15      */
16     void requestGet(String url);
17 
18     /**
19      * post請求
20      *
21      * @param url 請求地址
22      * @param obj 請求參數
23      */
24     void requestPost(String url, Object obj);
25 }
HttpClientProvider.java

 

 1 package com.example.httpclientdemo.biz.provider.impl;
 2 
 3 import com.alibaba.fastjson.JSON;
 4 import com.example.httpclientdemo.biz.provider.HttpClientProvider;
 5 import com.example.httpclientdemo.common.utils.http.client.HttpClientUtils;
 6 import org.apache.http.HttpEntity;
 7 import org.apache.http.client.methods.CloseableHttpResponse;
 8 import org.apache.http.client.methods.HttpGet;
 9 import org.apache.http.client.methods.HttpPost;
10 import org.apache.http.entity.StringEntity;
11 import org.apache.http.impl.client.CloseableHttpClient;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14 import org.springframework.stereotype.Service;
15 
16 import javax.annotation.Resource;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.nio.charset.StandardCharsets;
20 
21 /**
22  * HttpClient業務支撐接口實現類
23  *
24  * @author 復姓江山
25  * @date 2021/02/08
26  */
27 @Service
28 public class HttpClientProviderImpl implements HttpClientProvider {
29     private final Logger logger = LoggerFactory.getLogger(this.getClass());
30 
31     @Resource(name = "closeableHttpClient")
32     private CloseableHttpClient httpClient;
33 
34 
35     @Override
36     public void requestGet(String url) {
37         HttpGet httpGet = new HttpGet(url);
38         CloseableHttpResponse response = null;
39         InputStream inputStream = null;
40 
41         try {
42             response = HttpClientUtils.get(httpClient, httpGet);
43             HttpEntity httpEntity = response.getEntity();
44             inputStream = HttpClientUtils.getContent(httpEntity);
45             String respString = HttpClientUtils.getContentString(inputStream);
46             logger.debug("respString: {}", respString);
47         } catch (Exception e) {
48             e.fillInStackTrace();
49         } finally {
50             try {
51                 HttpClientUtils.close(response, inputStream);
52             } catch (IOException ioException) {
53                 ioException.printStackTrace();
54             }
55         }
56     }
57 
58     @Override
59     public void requestPost(String url, Object obj) {
60         HttpPost httpPost = new HttpPost(url);
61         String jsonString = JSON.toJSONString(obj);
62         httpPost.setEntity(new StringEntity(jsonString, StandardCharsets.UTF_8));
63         CloseableHttpResponse response = null;
64         InputStream inputStream = null;
65         try {
66             response = HttpClientUtils.post(httpClient, httpPost);
67             HttpEntity httpEntity = response.getEntity();
68             inputStream = HttpClientUtils.getContent(httpEntity);
69             String respString = HttpClientUtils.getContentString(inputStream);
70             logger.debug("respString: {}", respString);
71         } catch (Exception e) {
72             e.fillInStackTrace();
73         } finally {
74             try {
75                 HttpClientUtils.close(response, inputStream);
76             } catch (IOException ioException) {
77                 ioException.printStackTrace();
78             }
79         }
80     }
81 }
HttpClientProviderImpl.java

  8. HttpClient業務接口測試

  通過運行單元測試類來測試接口,下文有詳細的測試數據。

 1 package com.example.httpclientdemo.biz.service;
 2 
 3 import org.junit.jupiter.api.Test;
 4 import org.slf4j.Logger;
 5 import org.slf4j.LoggerFactory;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.boot.test.context.SpringBootTest;
 8 
 9 import java.util.concurrent.ExecutorService;
10 import java.util.concurrent.Executors;
11 import java.util.concurrent.atomic.AtomicInteger;
12 
13 import static org.junit.jupiter.api.Assertions.*;
14 
15 @SpringBootTest
16 class HttpClientServiceTest {
17     private final static Logger logger = LoggerFactory.getLogger(HttpClientServiceTest.class);
18 
19     @Autowired
20     private HttpClientService httpClientService;
21 
22     private static final String URL_GET_PATH = "https://www.baidu.com";
23 
24     private final AtomicInteger count = new AtomicInteger();
25 
26     /**
27      * workStealingPool
28      */
29     public final static ExecutorService workStealingPool = Executors.newWorkStealingPool(1<<6);
30 
31     @Test
32     void requestGet() throws InterruptedException {
33         final long startMils = System.currentTimeMillis();
34         final long statNanos = System.nanoTime();
35         for (int i = 0; i < 1000; i++) {
36             workStealingPool.execute(() -> {
37                 httpClientService.requestGet(URL_GET_PATH);
38                 logger.warn("requestGet, times: {}, betMils: {},betNanos: {}", count.getAndIncrement(),
39                         (System.currentTimeMillis() - startMils), (System.nanoTime() - statNanos));
40             });
41 
42         }
43         Thread.sleep(20000);
44     }
45 
46     @Test
47     void requestPost() {
48     }
49 }
HttpClientServiceTest.java

 

三、測試驗證

  本文測試方式可能不是那么專業與嚴謹,可是並不妨礙我們通過測試數據看出些原理,總結出些規律,也許有些片面,但可看出些趨勢。

1. 運行日志

 1 main 2021-02-09 14:09:34,963 DEBUG (PoolingHttpClientConnectionManager.java:267)- Connection request: [route: {s}->https://www.baidu.com:443][total available: 0; route allocated: 0 of 50; total allocated: 0 of 200]
 2 main 2021-02-09 14:09:34,978 DEBUG (PoolingHttpClientConnectionManager.java:312)- Connection leased: [id: 0][route: {s}->https://www.baidu.com:443][total available: 0; route allocated: 1 of 50; total allocated: 1 of 200]
 3 main 2021-02-09 14:09:34,980 DEBUG (MainClientExec.java:234)- Opening connection {s}->https://www.baidu.com:443
 4 main 2021-02-09 14:09:34,994 DEBUG (DefaultHttpClientConnectionOperator.java:139)- Connecting to www.baidu.com/14.215.177.38:443
 5 main 2021-02-09 14:09:34,994 DEBUG (SSLConnectionSocketFactory.java:366)- Connecting socket to www.baidu.com/14.215.177.38:443 with timeout 0
 6 main 2021-02-09 14:09:35,101 DEBUG (SSLConnectionSocketFactory.java:430)- Enabled protocols: [TLSv1, TLSv1.1, TLSv1.2]
 7 main 2021-02-09 14:09:35,101 DEBUG (SSLConnectionSocketFactory.java:431)- Enabled cipher suites:[TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
 8 main 2021-02-09 14:09:35,102 DEBUG (SSLConnectionSocketFactory.java:435)- Starting handshake
 9 main 2021-02-09 14:09:35,250 DEBUG (SSLConnectionSocketFactory.java:465)- Secure session established
10 main 2021-02-09 14:09:35,250 DEBUG (SSLConnectionSocketFactory.java:466)-  negotiated protocol: TLSv1.2
11 main 2021-02-09 14:09:35,250 DEBUG (SSLConnectionSocketFactory.java:467)-  negotiated cipher suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
12 main 2021-02-09 14:09:35,250 DEBUG (SSLConnectionSocketFactory.java:475)-  peer principal: CN=baidu.com, O="Beijing Baidu Netcom Science Technology Co., Ltd", OU=service operation department, L=beijing, ST=beijing, C=CN
13 main 2021-02-09 14:09:35,251 DEBUG (SSLConnectionSocketFactory.java:484)-  peer alternative names: [baidu.com, baifubao.com, www.baidu.cn, www.baidu.com.cn, mct.y.nuomi.com, apollo.auto, dwz.cn, *.baidu.com, *.baifubao.com, *.baidustatic.com, *.bdstatic.com, *.bdimg.com, *.hao123.com, *.nuomi.com, *.chuanke.com, *.trustgo.com, *.bce.baidu.com, *.eyun.baidu.com, *.map.baidu.com, *.mbd.baidu.com, *.fanyi.baidu.com, *.baidubce.com, *.mipcdn.com, *.news.baidu.com, *.baidupcs.com, *.aipage.com, *.aipage.cn, *.bcehost.com, *.safe.baidu.com, *.im.baidu.com, *.baiducontent.com, *.dlnel.com, *.dlnel.org, *.dueros.baidu.com, *.su.baidu.com, *.91.com, *.hao123.baidu.com, *.apollo.auto, *.xueshu.baidu.com, *.bj.baidubce.com, *.gz.baidubce.com, *.smartapps.cn, *.bdtjrcv.com, *.hao222.com, *.haokan.com, *.pae.baidu.com, *.vd.bdstatic.com, click.hm.baidu.com, log.hm.baidu.com, cm.pos.baidu.com, wn.pos.baidu.com, update.pan.baidu.com]
14 main 2021-02-09 14:09:35,251 DEBUG (SSLConnectionSocketFactory.java:488)-  issuer principal: CN=GlobalSign Organization Validation CA - SHA256 - G2, O=GlobalSign nv-sa, C=BE
15 main 2021-02-09 14:09:35,254 DEBUG (DefaultHttpClientConnectionOperator.java:146)- Connection established 192.168.100.24:63820<->14.215.177.38:443
16 main 2021-02-09 14:09:35,255 DEBUG (MainClientExec.java:255)- Executing request GET / HTTP/1.1
17 main 2021-02-09 14:09:35,255 DEBUG (MainClientExec.java:260)- Target auth state: UNCHALLENGED
18 main 2021-02-09 14:09:35,255 DEBUG (MainClientExec.java:266)- Proxy auth state: UNCHALLENGED
19 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:133)- http-outgoing-0 >> GET / HTTP/1.1
20 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:136)- http-outgoing-0 >> Host: www.baidu.com
21 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:136)- http-outgoing-0 >> Connection: Keep-Alive
22 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:136)- http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.12 (Java/1.8.0_161)
23 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:136)- http-outgoing-0 >> Accept-Encoding: gzip,deflate
24 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "GET / HTTP/1.1[\r][\n]"
25 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "Host: www.baidu.com[\r][\n]"
26 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
27 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.12 (Java/1.8.0_161)[\r][\n]"
28 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
29 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "[\r][\n]"
30 main 2021-02-09 14:09:35,300 DEBUG (Wire.java:73)- http-outgoing-0 << "HTTP/1.1 200 OK[\r][\n]"
31 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Content-Encoding: gzip[\r][\n]"
32 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Content-Length: 1145[\r][\n]"
33 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Content-Type: text/html[\r][\n]"
34 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Server: bfe[\r][\n]"
35 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Date: Tue, 09 Feb 2021 06:09:34 GMT[\r][\n]"
36 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "[\r][\n]"
37 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "[0x1f][0x8b][0x8][0x0][0x0][0x0][0x0][0x0][0x0][0xff][0x94]V[[0x8f][0xd4][0xb6][0x17]G[0xe2];[0x98][0xfc][0xb5][0xbb] 4[0xe3][0xb9][0x8][0xc1]7[0x9][0xda]nABH[0x5][0x15]V*O#[0xc7]v[0x12][0xb3][0x89]mlg[0xc2][0xf0][0xd4][0x95]J[0xd5][0xaa][0xa5][0xb4][0xa2][0x17]Q*[0xb5][0xaa]Z[0xb6][0xf][0x95][0xa0]*R[0xd1]R[0xe0][0xcb]L[0xd8][0xdd][0xa7]~[0x85][0xca]If[0xe7][\n]"
38 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "[0xa8][0xf3][0x12][0xfb][0xf8][0x9c][0xdf][0xf9][0x9d][0x9b]=[0xee][0xb1]w/m\[0xbd]v[0xf9][0x1c][0x88]M[0x9a][0xf8]G[0x8f][0xb8][0xc7][0x1a][0x8d]+W[0xd7][0xaf]n^[0x1][0x97].6[0x1a][0xbe][[0xca][0x81][0x1b]SD|7[0xa5][0x6][0x81][0xd8][0x18][0xd9][0xa0]72[0xd6][0xf7][0xb0][0xe0][0x86]r[0xd3]0[0x3]IA[0xbd][0xf1][0xc][0xbd]i[0xa0]5[[0xc3]1R[0x9a][0x1a]/3a[0xe3][0xcc][0xbc][0xf5][0x7][0x8d][0xcd][0xf5][0xc6][0x86]H%2,H[0xc6][0x0][0x17][0xce]y[0xe7]HDk[0x83][0x91][0x14]%9[0x1a]h[0xc0]QJ=EC[0xaa][0x14]U[0xbe][0x9b]0[0xbe][0x5][0x14]M<m[0x6][0x9][0xd5]1[0xa5][0x6]X6[0x15][0xb][0xac]5[0x88][0x15][\r]=[0xeb]U[0xaf]B[0xa8]u[0xbb][0x19][0x10]m[0x90]a[0xb8][0x89]E[\n]"
39 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "O[0xd1][0xf7][0xda][0xc1][0xf5][0x1b]g[0xd6][0xd7]7[0xaf][0xa5][0x9d][[0x91][0xb8][0xd6][0xbd][0x8][0x15][0xcc][0xf3][0x1c]b[0x84]c[\n]"
40 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "[0x3]"[0xd4]-[0x18] F[0xb2]f[0xca]x[0x13]k[0xed][0xbb][0x86][0x99][0x84][0xfa]{[0xf7]_[0x14][0xbb][0xf][0x87]O?[0x1c]>[0xfd][0xec][0x9f][0xbf]?[0x1f]>[0xff][0xa9]x[0xfc][0xc7][0xde][0x8f][0xbf][0x1e]l[0xdf]sa[0xa5][0xe2][0xc2]2q[0xc0][\r][0x4][0x19][0x0]K[0xd6][0xfb]_[0xab][0xd5]ja[0xec][0x3][0x97][0xb0]>`[0xc4][0xcb][0x15][0x92][0x92][0xaa][0xb1][0xa0]6[0xb1];[0x9c] [0xad]KAoZ[0xad]:[0xd0][0xbd]P[0xa8]t[0x81][0xa8]7[0x7][0x9a]D>pY[0x1a][0x81][0x98][0x11][0x1a][\n]"
41 main 2021-02-09 14:09:35,303 DEBUG (Wire.java:73)- http-outgoing-0 << "[0x9c]i[0xcf][0xa8][0x8c][0x2][0xad][0xb0][0x7]m[0xbc][0xcd]*F[0x9b][0x14][0x96]F0 [0xbd]DD[0xa2][0xdd][0x94]<[0x2]9#&[0xf6]:[0xa7][ [0xa6],[0x8a][0x8d][0xd7][0xee][0xfc][0xdf][0x7].$[0xac][0xef][0x3][0xd7]:[0xb4].[0xca]oY[0x9f][0x10] l[0x98][0xe0]s[0xc8][0xba]f[0x19]Z[0xd2][0x8c][0xcb][0xac][0xae]V[0xcc][0x8][0xa1][0xbc]2.3[0xde][0xc3]"[0xa5][0xa0][0x8f][0x92][0x8c]z[0xed][0xd7][0xeb][0xb2][0x91]N[0xd5]b[0xaf][0xd5][0xb]k[0xb5]7[0xa8]([0xdd][0xef][0x5][0xf2][0xed].[0xad][0x1e]#7[0xdf][0xae]hx[0xad]S[0x86][0xef][0xbb]Z"^[0x87][0xef][0x4][0x11][0xd0]=&M/W[0x8e]_[0x3]0[0xe2]m[0xe5][0x95]iN[0xe][0xab][0xc9][0xa4][0xa9]`@[0x8a]n&[0x94]G[0xb6][0x10][0xa7]N[0x1][0x94][0x19][0x81]E*[0x13]j[0xa8]'[0xc2][0xb0][0x14]Tu=\[0xf9].[0xb4]N[0x17][0xb8][0xe][0xc][0x9f]t]r[0xd7]Y[0x90][0xb2][0x92][0x86][0xce]j[0xe6][0x93][0x1d]>k[0xef][0x80]9?[0xc0][0x85]u?[0xd6][0x9d]Q[0xea][0x16][0xcc]l[0xb2][0xd0]x W![0xe4]4[0xd7][0xe3][0xf6][0xa8][0xf3]v[0xbd]g[0x94]=[0xa8]=[0xa6][0x1c][0xf5][0xfd]W[0xdf]>>[0xf8][0xee][0x99][0xb][0xd1]4[0x84][0x9d]i[0xdb]a1[0x12][0xed]Nw[0x6][0xa3][0x12]N[0xa2]T[0x92]9[0x94]U[0x8]S$[0x17][0xf2]H[0x91][0x9c][0x4](~x\<x[0xb1][0x8][0xa0][0xbf][0xd0][0xbc][0xcf][0x8][0x15][0x93][0x0][0xfb];[0x1f][0x1f][0xfc][0xfc][0xd5]"[0x0][0xc3]h[0x80][0x16][0x82][0x94]'S O[0x9e][0x14]_[0xee]T \h[0xac][0x98]4sx[0xd3][0x83]W]c[0x89][0x88][0x18]oF,<[[0xae][0x96]Q*[0xd7][0x8c]L[0xbc][0xb4]Zf[0xa5][0xed]Rw}[0xa9]s~[0xa9]s~[\n]"
42 main 2021-02-09 14:09:35,303 DEBUG (Wire.java:73)- http-outgoing-0 << "a[0xa9][0x13].u[0xc3][0xf1]l.uI[0xfb][0x90]c[0x89]V3L[0x2][0xef][0xfe][0xb3][0xe2][0xf9]7[0x15]?8A[0xb0]^[0x10][0x81][0xb3][0x94]r[0xd3][0xcc][0x15]3[0xf4][0xf8][0xca][0x88][0xb8][0xf3][0x1f][0x98][0xd7][0xac]3o[0xe5]$[0xa0][0x1c][0xb]B7[0xdf][0xbf]`[0xdf][0x12][0xc1])7[0xc7]s[0xc6][0x89][0xc8][0x9b][0x89][0xc0][0xc8][0xde]CM[0x8b][0x12][0xcc][0x89]5E[\n]"
43 main 2021-02-09 14:09:35,303 DEBUG (Wire.java:73)- http-outgoing-0 << "[0xc7][0xc0][0xf3]<[0xe0]8[0xe0],p[0xce]:`[0x15]8[0xcb][0xce][0x89][0x93][0xc0][0x19][0xc7][0xea][0xb5][0xad]`[0xc5][0xa9][0xe2]uF[0x1];[0xa3][0x91]H[0x2]g"[0xe6][0x95][0x13]kG[0x8f][0x80][0x99][0x9f][0xb]g[0xcb]4[0x1b]g*[0x14][0x85][0x87][0x19][\r][0x14]cX[0x8c]r[0x1a]([0x6][0xca][0x7][0xce]s[0x8][0xd3]2A[0x83]U[0x10]$[0x2]o[0xad]9[0xfe][0xab][0x7]O[0x8a]_[0xbe][0x1f][0xee][0xee][0x14][0xf7][0xb6][0xeb][0x94]O[\r][0xdf][0xf4][0xc][0x86]fC[0xf0][0x99]m[0xee][0x3]W[0x96]oD<[0xd7]E[0xb1]H[0xe9][0x98][0xa4]_[0xdc][0xfe]s[0xb8][0xfb]Eu-,jb[0xa6]&[0x94][0xd7][0x3][0x91][0x19][0xf0][0x8e][0xdd][0xd7][0xc4][0xe4][0xc8][0x13][0x96][0xfe]2[0x16]r[0xb0][0xd6]i[0xb5]O/[0xf3]@[0xcb][0xb5]R[0xaf]Z[0xbe][0xb1][0x93]If[0x6][0xd0][0x1f]>[0xb9][0xf7][0xf5]o[0x15][0x91][0xe2][0xd3];[0xc5][0xcb][0xdb][0xfb][0x8f][0xca][0xeb][0xa1]B[0x98][0xe5]u[0x9d]!>`[0x13](ub[0xb1]l[0x84][0x94][0x92][0x0][0xe1]-[0xff][0xd5]Gw[0xf7]w[0xb6][0x8b][0xbb]w[0xe][0x1e]~2F[0x1a][0xee][0xfe]~a[0xe3][0xf2][0xfe][0xa3][0xed]V[0xb7][0xd5]>[0xdd]-[0xee][0xfe]5[0xf2]`[0x1f][0xd3][0xd7][0xbd][0x9e][0x91][0xb6][0xbd]:[\n]"
44 main 2021-02-09 14:09:35,303 DEBUG (Wire.java:87)- http-outgoing-0 << "yaA[0xa0][0xfd]K`[0xbf][0xf5]?[0xaf][0x3][0x0][0x0][0xff][0xff]0[0xc][0x81][0x9a][0x8b][0x9][0x0][0x0]"
45 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:122)- http-outgoing-0 << HTTP/1.1 200 OK
46 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Content-Encoding: gzip
47 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Content-Length: 1145
48 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Content-Type: text/html
49 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Server: bfe
50 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Date: Tue, 09 Feb 2021 06:09:34 GMT
51 main 2021-02-09 14:09:35,310 DEBUG (MainClientExec.java:285)- Connection can be kept alive indefinitely
52 main 2021-02-09 14:09:35,316 DEBUG (HttpClientProviderImpl.java:46)- respString: <!DOCTYPE html>
53 <!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新聞</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地圖</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>視頻</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>貼吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登錄</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登錄</a>');
54                 </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多產品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>關於百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必讀</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意見反饋</a>&nbsp;京ICP證030173號&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
55 main 2021-02-09 14:09:35,318 DEBUG (PoolingHttpClientConnectionManager.java:344)- Connection [id: 0][route: {s}->https://www.baidu.com:443] can be kept alive indefinitely
56 main 2021-02-09 14:09:35,318 DEBUG (LoggingManagedHttpClientConnection.java:88)- http-outgoing-0: set socket timeout to 0
57 main 2021-02-09 14:09:35,318 DEBUG (PoolingHttpClientConnectionManager.java:351)- Connection released: [id: 0][route: {s}->https://www.baidu.com:443][total available: 1; route allocated: 1 of 50; total allocated: 1 of 200]
58 main 2021-02-09 14:09:35,319 WARN (HttpClientServiceTest.java:80)- requestGet, times: 0, betMils: 403,betNanos: 402522300
httpClientLog

2. 綜合比較

  maxTotal:200

Threads

defaultMaxPerRoute

validateAfterInactivity

betMils

betNanos

 256

 

 

 

 

 20

 1500

 

 

 

 

 5270

5269994599 

 50

 

4310

 

4310753100

 

100

 

4513

 

4512503700

 

150

 

4963

 

4962632601

 

200

 

5245

 

5244764201

 

1024

 

 

 

20

 1500

 

 

5087

 

5087564601

 

50

 

4323

 

4323088301

 

64

  

 

 

 

50

  

 

 

 

15000

 

3900

 

3900514800

 

2000(default)

 

3531

 

3537111900

0

3358

3355394500

32

 

 

50

 

 

0

3471

 

3456438200

 

2000(default)

 

2918

 

2912550800

 50

 

 

 

 

 

 50

 

 

 

 

 

 

15000

 

2847

 

2846675400

0

3190

3189325400

2000(default)

3263

3264044800

1000

2741

2740233600

500

2802

2801841600

800

 

2800

 

2800641400

  

  根據以上數據我們能看出什么呢?

  在分析數據以前我先羅列一下電腦配置:

  Windows 10 專業版

  Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz 3.00 GHz 4核

  16.0 GB

  64 位

  SSD 232.89 GB

 

  首先根據本機硬件及系統配置,多線程可以提高系統的並發效率,但是也不是絕對的,大致在50個線程的時候效果較好。然后defaultMaxPerRoute參數也是50,即每個路由默認並行接受的請求數。因為本文的測試目標服務器是百度,百度服務器設置連接時間可無限期的保持“Connection can be kept alive indefinitely”,調節validateAfterInactivity參數,總的來說效果不是很大,當然需要排除網絡請求的一些影響因素,比如擁塞、路由等情況,可根據下表的參數比較知道,即使相同的配置參數,不同時間點請求服務器,響應的時長也有差異,也就是說每一次的網絡請求都是必然中的一次偶然情況。

3. 同參數比較

  Threads: 50 

  maxTotal: 200

  defaultMaxPerRoute:50

  validateAfterInactivity:1000

  idleTimeOut:3

betMils

betNanos

2813

2813779600

3228

3229129100

3030

3030484200

2806

2805046900

2981

2981383600

2629

2629455200

2814

2813863100

2747

2747754700

2748

2747132800

3365

3365044500

 

  通過上表可以看出,每一次網絡請求在同一網絡情況下或相似網絡情況下,響應的時長差距不大。但因為影響網絡的因素眾多,導致每次響應的時長都不一樣。

 四、后記

  暫時先分享到此,后期會有補充的,比如源碼、架構等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM