这两天使用httpclient4.3.5(好像httpclient每个版本差别挺大的)访问一个https的服务,发现跑一段时间后有连接在createLayeredSocket的时候卡住,并且一直不超时释放,线程调用栈:
"Thread-12" daemon prio=10 tid=0x00002aaab488a000 nid=0x4b02 runnable [0x0000000042712000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:830)
- locked <0x000000078309d398> (a java.lang.Object)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
- locked <0x000000078309d4a0> (a java.lang.Object)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:275)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:254)
at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:123)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:318)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
google了一圈,httpclient有个几个超时时间需要设置,少设置了PoolingHttpClientConnectionManager中DefaultSocketConfig的超时时间。
在使用连接池的情况下,访问https请求。httpClient超时的设置包括两个位置:
1 httppost.setConfig(requestConfig); 通过执行的http请求设置RequestConfig。
RequestConfig包括setConnectionRequestTimeout分配等待连接池分配的超时时间、setConnectTimeout建立网络连接的超时时间、setSocketTimeout 通讯过程中的超时时间。
2 PoolingHttpClientConnectionManager.setDefaultSocketConfig;连接管理器设置设置默认socket 超时时间,SocketConfig.Builder.setSoTimeout方法。
执行设置了RequestConfig的https请求时,处理过程如下:
与超时时间相关的位置:
A 从连接池获取连接,最长的等待时间,使用RequestConfig. getConnectionRequestTimeout。
B 创建socket对象,使用SocketConfig . getSoTimeout设置socket的soTimeout.
C socket建立网络连接,使用RequestConfig.getConnectTimeout作为发起连接的超时时间。
D createLayeredSocket完成SSL握手处理,使用socket的超时时间(就是B设置的SocketConfig . getSoTimeout)。
E 使用RequestConfig.getSocketTimeout设置分配的Socket的soTimeout。后续处理过程就用这个超时时间了。