Java HttpClient中的三种超时设置区别
来源:互联网 发布:淘宝账号是不是会员名 编辑:程序博客网 时间:2024/05/22 13:03
最近项目中在使用HttpClient有三个超时(connectionRequestTimeout,connectTimeout,socketTimeout)时间理解得不是很透彻,API文档不是很理解,专门写Demo理解了一下。
API的描述如下:
/** * Returns the timeout in milliseconds used when requesting a connection * from the connection manager. A timeout value of zero is interpreted * as an infinite timeout. * <p> * A timeout value of zero is interpreted as an infinite timeout. * A negative value is interpreted as undefined (system default). * </p> * <p> * Default: {@code -1} * </p> */ public int getConnectionRequestTimeout() { return connectionRequestTimeout; } /** * Determines the timeout in milliseconds until a connection is established. * A timeout value of zero is interpreted as an infinite timeout. * <p> * A timeout value of zero is interpreted as an infinite timeout. * A negative value is interpreted as undefined (system default). * </p> * <p> * Default: {@code -1} * </p> */ public int getConnectTimeout() { return connectTimeout; } /** * Defines the socket timeout ({@code SO_TIMEOUT}) in milliseconds, * which is the timeout for waiting for data or, put differently, * a maximum period inactivity between two consecutive data packets). * <p> * A timeout value of zero is interpreted as an infinite timeout. * A negative value is interpreted as undefined (system default). * </p> * <p> * Default: {@code -1} * </p> */ public int getSocketTimeout() { return socketTimeout; }
正确解读一下
API中不能看出正式的含义是什么,经过demo之后,终于知道了各自含义
1. connectTimeOut:指建立连接的超时时间,比较容易理解
2. connectionRequestTimeOut:指从连接池获取到连接的超时时间,如果是非连接池的话,该参数暂时没有发现有什么用处
3. socketTimeOut:指客户端和服务进行数据交互的时间,是指两者之间如果两个数据包之间的时间大于该时间则认为超时,而不是整个交互的整体时间,比如如果设置1秒超时,如果每隔0.8秒传输一次数据,传输10次,总共8秒,这样是不超时的。而如果任意两个数据包之间的时间超过了1秒,则超时。
代码
首先是为这次demo写的服务代码,包含几个controller方法(Spring MVC)
package me.nabil.demo.springbootdemo;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * 超时测试 * * @author nabilzhang */@Controller@EnableAutoConfiguration@RequestMapping(value = {"/test"}, method = {RequestMethod.GET})public class TimeoutTestController { private static final Logger logger = LoggerFactory.getLogger(TimeoutTestController.class); /** * main方法 * * @param args 参数数组 */ public static void main(String args[]) { SpringApplication.run(TimeoutTestController.class, args); } /** * 1.测试socketOutTimeout,三秒后返回数据 * * @return * @throws InterruptedException */ @RequestMapping(value = {"/socket_timeout"}, method = {RequestMethod.GET}) @ResponseBody String socketTimeout() throws InterruptedException { logger.info("socket_timeout"); Thread.sleep(3000); return "socket_timeout"; } /** * 2.测试socketOutTimeout,每隔0.8秒返回数据 * * @return * @throws InterruptedException */ @RequestMapping(value = {"/socket_timeout_2"}, method = {RequestMethod.GET}) void socketTimeout2(HttpServletResponse response) throws InterruptedException, IOException { logger.info("socket_timeout_2"); for (int i = 0; i < 10; i++) { logger.info("{}", i); response.getWriter().println("" + i); response.flushBuffer(); Thread.sleep(800); } } /** * 3.测试connectionRequestTimeout用的服务,三秒后返回数据 * * @param request * @return * @throws InterruptedException */ @RequestMapping(value = {"/connection_request_timeout"}, method = {RequestMethod.GET}) @ResponseBody String connectionRequestTimeout(HttpServletRequest request) throws InterruptedException { logger.info("{}", request.getRequestURI()); Thread.sleep(3000); return "connectionRequestTimeout"; }}
如下是客户端的测试Case,下面几个Case分别测试了几个超时时间的各种情况,Case全部通过才可以
package me.nabil.demo.springbootdemo;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.conn.ConnectTimeoutException;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.impl.conn.BasicHttpClientConnectionManager;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;import org.apache.http.util.EntityUtils;import org.junit.Assert;import org.junit.Test;import java.io.IOException;import java.net.SocketTimeoutException;import java.util.Date;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 测试HttpClient超时参数 * * @author nabilzhang */public class TimeoutTestControllerTest { /** * 1.connectionTimeout测试:IP无法链接,链接超时 * * @throws Exception */ @Test public void connectionTimeout() throws Exception { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet("http://74.125.203.100"); RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(1000) .setSocketTimeout(1000).setConnectTimeout(1000).build(); httpGet.setConfig(requestConfig); try { httpclient.execute(httpGet); } catch (ConnectTimeoutException exception) { Assert.assertTrue(exception.getMessage().contains("connect timed out")); } } /** * 2.socketTimeout测试,服务端没有指定时间内任何响应,会超时 * * @throws Exception */ @Test public void socketTimeout() throws Exception { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/test/socket_timeout"); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(1000).build(); httpGet.setConfig(requestConfig); try { httpclient.execute(httpGet); } catch (SocketTimeoutException exception) { Assert.assertEquals("Read timed out", exception.getMessage()); } } /** * 3.socketTimeout测试:服务端隔800ms返回一点数据,不会超时 * * @throws Exception */ @Test public void socketTimeoutNo() { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/test/socket_timeout_2"); RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(1000) .setSocketTimeout(1000).setConnectTimeout(1000).build(); httpGet.setConfig(requestConfig); try { httpclient.execute(httpGet); CloseableHttpResponse response = httpclient.execute(httpGet); System.out.println(String.format("socketTimeoutNo, %s", EntityUtils.toString(response.getEntity()))); } catch (Exception e) { Assert.fail("服务端隔800ms返回一点数据,不会超时"); } } /** * 4.connectionRequestTimeout测试:指从连接管理器(例如连接池)中拿到连接的超时时间 * * @throws Exception */ @Test public void connectionRequestTimeoutWithPoolingConnectionManager() throws Exception { PoolingHttpClientConnectionManager conMgr = new PoolingHttpClientConnectionManager(); conMgr.setMaxTotal(2); final CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(conMgr).build(); final HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/test/connection_request_timeout"); RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(1000) .setConnectionRequestTimeout(1000).setSocketTimeout(1000).build(); httpGet.setConfig(requestConfig); // 如下多线程占满连接池 ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { executorService.submit(new Runnable() { @Override public void run() { try { CloseableHttpResponse response = httpclient.execute(httpGet); System.out.println(String.format("connectionRequestTimeoutTest: %s", EntityUtils.toString(response.getEntity()))); } catch (SocketTimeoutException exception) { System.out.println(exception.getMessage()); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); } // 在连接池占满的情况下,拿不到就会抛异常 try { CloseableHttpResponse response = httpclient.execute(httpGet); System.out.println(String.format("connectionRequestTimeoutTest: %s", EntityUtils.toString(response.getEntity()))); Assert.fail(); } catch (Exception exception) { // 异常是从连接池拿到连接超时 Assert.assertEquals("Timeout waiting for connection from pool", exception.getMessage()); System.out.println(exception.getMessage()); } } /** * 5.connectionRequestTimeout测试,指从连接管理器中拿到连接的超时时间,由于使用基本的连接管理器,链接被占用时,直接无法分配链接 * connectionRequestTimeout并未生效,目前看来该参数只在连接池奏效. * 该链接管理器(BasicHttpClientConnectionManager)是单线程情况下可以使用,多线程情况下不要使用。 * * @throws Exception */ @Test public void connectionRequestTimeoutWithBasicConnectionManager() throws Exception { BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(); final CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(connManager).setMaxConnPerRoute(1).build(); final HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/test/connection_request_timeout"); RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(100000) .setConnectionRequestTimeout(1000000).setSocketTimeout(1000000).build(); httpGet.setConfig(requestConfig); // 如下多线程占满连接 ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { executorService.submit(new Runnable() { @Override public void run() { CloseableHttpResponse response = null; try { response = httpclient.execute(httpGet); System.out.println(String.format("connectionRequestTimeoutTest: %s", EntityUtils.toString(response.getEntity()))); } catch (Exception exception) { exception.printStackTrace(); } finally { if (response != null) { try { response.close(); httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } } } }); } System.out.println(new Date()); // 在连接池占满的情况下,拿不到就会抛异常 try { CloseableHttpResponse response = httpclient.execute(httpGet); System.out.println(String.format("connectionRequestTimeoutTest: %s", EntityUtils.toString(response.getEntity()))); Assert.fail(); } catch (Exception exception) { System.out.println(new Date()); exception.printStackTrace(); // 异常是从连接池拿到连接超时 Assert.assertEquals("Connection is still allocated", exception.getMessage()); System.out.println(exception.getMessage()); } }}
注:上面Case是使用httpclient版本4.5.2测试所得。
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> <type>jar</type> </dependency>
更深理解可以参照:http://www.baeldung.com/httpclient-connection-management
阅读全文
0 0
- Java HttpClient中的三种超时设置区别
- HttpClient中的三种超时设置区别
- Java中httpClient中的三种超时设置小结
- Java中httpClient中的三种超时设置小结
- Java中httpClient中的三种超时设置小结
- httpClient中的三种超时设置
- httpClient中的三种超时设置总结
- httpClient中的三种超时时间设置
- httpClient中的三种超时
- Java中httpClient中的三种超时设置小结(转)
- Java中httpClient中的设置超时时间
- Java笔记:HttpClient超时设置
- HttpClient的三种超时
- HttpClient的三种超时
- Java中httpClient中三种超时设置
- HttpClient超时设置
- httpclient 超时设置
- tornado httpclient 超时设置
- left join (on 和 where条件放置的区别)
- spring cloud eureka server 配置
- 【Python-2.7】list类型
- Kernel 中的 GPIO 定义和控制
- Java的体系结构
- Java HttpClient中的三种超时设置区别
- 统计一个字符串中出现次数最多的字符
- 【PostgreSQL-9.6.3】使用pg_settings表查看参数的生效条件
- 关于JSP form的默认提交方式
- linux日志分析
- 【论文笔记】GAN-摘要-201709
- 又双叒叕一个软件安装方法
- #display:block、inline、inline-block的区别#
- 安卓,调用系统方法分享到微信