Using HttpClient properly to avoid CLOSE_WAIT TCP connections
Apache的HttpComponent组件,用的人不在少数。但是能用好的人,却微乎其微,为什么?很简单,TCP里面的细节实现不是每个人都能捕获到的(细节是魔鬼),像并发请求控制&资源释放,Nagle算法参数优化,Connection eviction,跟ulimit配对的total connection,重定向策略定制化,两类超时时间的合理设置,流读写等等。
在最近的项目中,更是破天荒的遇到了close_wait问题,所以利用业余时间索性将之前同学写的HttpClient优化了一遍。下面我将贴出代码,如果大家发现了还有改进的余地,记得千万要留言知会我,共创最棒的代码:
/**
* 史上最棒的HttpClient4封装,details please see
* http://hc.apache.org/httpcomponents-client-ga/tutorial/html/index.html
*
* @author von gosling 2013-5-7
*/
public class HttpClientManager { //Consider ulimit
private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 7500;
//notice IE 6,7,8
private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 200; private static final int DEFAULT_CONN_TIMEOUT_MILLISECONDS = 5 * 1000; private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = 60 * 1000; private static final int INIT_DELAY = 5 * 1000; private static final int CHECK_INTERVAL = 5 * 60 * 1000; private static String HTTP_REQUEST_ENCODING = "UTF-8";
private static String LINE_SEPARATOR = "\r\n"; private static final Logger LOG = LoggerFactory
.getLogger(HttpClientManager.class); private static ThreadSafeClientConnManager connectionManager;
static {
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
//schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory())); connectionManager = new ThreadSafeClientConnManager(schemeRegistry);
connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);
connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE); //Connection eviction
ScheduledExecutorService scheduledExeService = Executors.newScheduledThreadPool(1,
new DaemonThreadFactory("Http-client-ConenctionPool-Monitor"));
scheduledExeService.scheduleAtFixedRate(new IdleConnectionMonitor(connectionManager),
INIT_DELAY, CHECK_INTERVAL, TimeUnit.MILLISECONDS);
} public static String doPost(String reqURL, Map<String, String> params, String encoding,
Boolean enableSSL) {
HttpClient httpClient = getHttpClient(enableSSL); String responseContent = "";
try {
HttpPost httpPost = buildHttpPostRequest(reqURL, params, encoding);
HttpResponse response = httpClient.execute(httpPost); // validateResponse(response, httpPost); HttpEntity entity = response.getEntity();
if (entity != null) {
// responseLength = entity.getContentLength();
responseContent = EntityUtils.toString(entity, encoding);
//Ensure that the entity content has been fully consumed and the underlying stream has been closed.
EntityUtils.consume(entity);
} else {
LOG.warn("Http entity is null! request url is {},response status is {}", reqURL,
response.getStatusLine());
}
} catch (ConnectTimeoutException e) {
LOG.warn(e.getMessage());
} catch (SocketTimeoutException e) {
LOG.warn("Read time out!");
} catch (SSLPeerUnverifiedException e) {
LOG.warn("Peer not authenticated!");
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return responseContent;
} public static String doPost(String reqURL, final String entities, String encoding) {
HttpClient httpClient = getHttpClient(false); String responseContent = "";
try {
AbstractHttpEntity printWriterEntity = new AbstractHttpEntity() {
public boolean isRepeatable() {
return false;
} public long getContentLength() {
return -1;
} public boolean isStreaming() {
return false;
} public InputStream getContent() throws IOException {
// Should be implemented as well but is irrelevant for this case
throw new UnsupportedOperationException();
} public void writeTo(final OutputStream outstream) throws IOException {
PrintWriter writer = new PrintWriter(new OutputStreamWriter(outstream,
HTTP_REQUEST_ENCODING));
writer.print(entities);
writer.print(LINE_SEPARATOR);
writer.flush();
} };
HttpPost httpPost = new HttpPost(reqURL);
//If the data is large enough that you need to stream it,
//you can write to a temp file and use FileEntity or possibly set up a pipe and use InputStreamEntity
httpPost.setEntity(printWriterEntity);
HttpResponse response = httpClient.execute(httpPost); validateResponse(response, httpPost); HttpEntity entity = response.getEntity();
if (entity != null) {
responseContent = EntityUtils.toString(entity, encoding);
//Ensure that the entity content has been fully consumed and the underlying stream has been closed.
EntityUtils.consume(entity);
} else {
LOG.warn("Http entity is null! request url is {},response status is {}", reqURL,
response.getStatusLine());
}
} catch (SocketTimeoutException e) {
LOG.warn("Read time out!");
} catch (SSLPeerUnverifiedException e) {
LOG.warn("Peer not authenticated!");
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return responseContent;
} private static X509TrustManager customTrustManager(HttpClient httpClient) {
//Trusting all certificates
X509TrustManager xtm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
} public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
} public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
try {
SSLContext ctx = SSLContext.getInstance("TLS");
if (null != ctx) {
ctx.init(null, new TrustManager[] { xtm }, null);
SSLSocketFactory socketFactory = new SSLSocketFactory(ctx,
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
httpClient.getConnectionManager().getSchemeRegistry()
.register(new Scheme("https", 443, socketFactory));
}
} catch (Exception e) {
LOG.error(e.getMessage());
} return xtm;
} private static HttpClient getHttpClient(Boolean enableSSL) {
DefaultHttpClient httpClient = new DefaultHttpClient(connectionManager);
httpClient.setRedirectStrategy(new RedirectStrategy() { //设置重定向处理方式为自行处理
@Override
public boolean isRedirected(HttpRequest request, HttpResponse response,
HttpContext context) throws ProtocolException {
return false;
} @Override
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response,
HttpContext context) throws ProtocolException {
return null;
}
}); httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,
DEFAULT_READ_TIMEOUT_MILLISECONDS);
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
DEFAULT_CONN_TIMEOUT_MILLISECONDS);
//According to http use-case to decide to whether to open TCP_NODELAY option,So does SO_LINGER option
httpClient.getParams().setParameter(CoreConnectionPNames.TCP_NODELAY, Boolean.TRUE);
httpClient.getParams().setParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK,
Boolean.FALSE); if (enableSSL) {
customTrustManager(httpClient);
} return httpClient;
} public static Map.Entry<Integer, String> doGetHttpResponse(String url, String encoding) {
HttpClient httpClient = getHttpClient(false);
HttpGet httpget = new HttpGet(url);
try {
EncodingResponseHandler responseHandler = new EncodingResponseHandler(); if (StringUtils.isBlank(encoding)) {
encoding = HTTP_REQUEST_ENCODING;
}
responseHandler.setEncoding(encoding); return httpClient.execute(httpget, responseHandler);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return null;
} public static String doGet(String url, String encoding) {
Map.Entry<Integer, String> ret = doGetHttpResponse(url, encoding);
if (ret == null) {
return "";
}
if (ret.getKey() != HttpStatus.SC_OK) {
LOG.error(
"Did not receive successful HTTP response: status code = {}, request url = {}",
ret.getKey(), url);
} return ret.getValue();
} public static void doPost(String url, Map<String, String> params) {
HttpClient httpClient = getHttpClient(false);
try {
HttpPost httpPost = buildHttpPostRequest(url, params, HTTP.UTF_8);
ResponseHandler<byte[]> handler = new ResponseHandler<byte[]>() {
public byte[] handleResponse(HttpResponse response) throws ClientProtocolException,
IOException {
HttpEntity entity = response.getEntity();
if (entity != null) {
return EntityUtils.toByteArray(entity);
} else {
return null;
}
}
};
httpClient.execute(httpPost, handler);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
} private static HttpPost buildHttpPostRequest(String url, Map<String, String> params,
String encoding)
throws UnsupportedEncodingException {
HttpPost httpPost = new HttpPost(url);
//Encode the form parameters
if (!CollectionUtils.isEmpty(params)) {
List<NameValuePair> nvps = Lists.newArrayList();
Set<Entry<String, String>> paramEntrys = params.entrySet();
for (Entry<String, String> entry : paramEntrys) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));
}
return httpPost;
} // private static void validateResponse(HttpResponse response, HttpGet get) throws IOException {
// StatusLine status = response.getStatusLine();
// if (status.getStatusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) {
// LOG.warn(
// "Did not receive successful HTTP response: status code = {}, status message = {}",
// status.getStatusCode(), status.getReasonPhrase());
// get.abort();
// return;
// }
// } private static void validateResponse(HttpResponse response, HttpPost post) throws IOException {
StatusLine status = response.getStatusLine();
if (status.getStatusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) {
LOG.warn(
"Did not receive successful HTTP response: status code = {}, status message = {}",
status.getStatusCode(), status.getReasonPhrase());
post.abort();
return;
}
} }
Using HttpClient properly to avoid CLOSE_WAIT TCP connections的更多相关文章
- Configure the max limit for concurrent TCP connections(转)
To keep the TCP/IP stack from taking all resources on the computer, there are different parameters t ...
- 【转载】Configure the max limit for concurrent TCP connections
转载地址:http://smallvoid.com/article/winnt-tcpip-max-limit.html To keep the TCP/IP stack from taking al ...
- Managing TCP Connections in Dynamic Spectrum Access Based Wireless LANs
2010年IEEE Secon的一篇文章.当然了,应该是之前就写好了,发表过,还是直接投到Secon了呢?直接投的吧,Secon不接受已发表过的吧. 本文的着笔点:有线网与DSAN(启用了DSA特性的 ...
- FIN vs RST in TCP connections different
question: The way I understand this, there are 2 ways to close TCP connection: send FIN flag send RS ...
- 从问题看本质: 研究TCP close_wait的内幕
Socket应用服务器TomcatOSUbuntu /* * @author: ahuaxuan * @date: 2010-4-30 */ 最近遇到的一个关于socket.close的问题,在某个 ...
- TCP之close_wait
TCP之close_wait 浏览:3697次 出处信息 /* * @author: ahuaxuan * @date: 2010-4-30 */ 查看各状态连接数: netstat -n | aw ...
- 使用httpclient抓取时,netstat 发现很多time_wait连接
http://wiki.apache.org/HttpComponents/FrequentlyAskedConnectionManagementQuestions 1. Connections in ...
- LINUX 中的 TCP/IP协议 参数详解
Ipsysctl tutorial 1.0.4 Prev Chapter 3. IPv4 variable reference Next https://www.frozentux.net/ipsys ...
- IP, TCP, and HTTP--reference
IP, TCP, and HTTP Issue #10 Syncing Data, March 2014 By Daniel Eggert When an app communicates with ...
随机推荐
- c# 字符串编码问题
一. ASCII码 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte). ...
- table的border-collapse属性与border-spacing属性
table border-collapse:collapse; 表示边框合并在一起. border-collapse:separate;表示边框之间的间距,间距的大小用border-spacing:p ...
- OLEDB 连接EXCEL的连接字符串IMEX的问题(Oledb)
今天碰到一个问题需要想EXCEL表中写数据,折腾了好久才发现是IMEX惹得祸,所以记录下提醒自己,也希望大家不要出同样的错. 碰到问题:使用语句 "insert into [Sheet1$] ...
- Jquery.Sorttable 桌面拖拽自定义
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- Android Design Support Library: 学习CoordinatorLayout
简述 CoordinatorLayout字面意思是"协调器布局",它是Design Support Library中提供的一个超级帧布局,帮助我们实现Material Design ...
- 用Spring Boot零配置快速创建web项目(1)
一.Spring Boot简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人 ...
- 关于<%@ include file=" " %>与<jsp:include page=""></jsp:include>中的那些问题?
今天在使用<%@ include file=" " %>指令时,竟然在页面中不让使用?这是怎么回事:问题如下图: 顿时被这个问题给搞到了!!!突然想到在以前的 JSP ...
- 迭代器(iterator) 与 traits 编程技法
看了候哥的<STL源码剖析>的迭代器那一章,在这里将思路稍微疏理一下 迭代器 迭代器模式的定义:提供一种方法,在不需要暴露某个容器的内部表现形式情况下,使之能依次访问该容器中的各个元素. ...
- python的hashlib模块
# -*- coding: utf-8 -*- """python 的MD5 sha1 模块""" import hashlib #md5的 ...
- HTML5 canvas中的转换方法
转换方法 scale(scalewidth,scaleheight) 缩放当前绘图至更大或更小 scalewidth 缩放当前绘图的宽度 (1=100%, ...