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 ...
随机推荐
- 以下各节已定义,但尚未为布局页“~/Views/Shared/_Layout.cshtml”呈现:“Scripts”。
以下各节已定义,但尚未为布局页“~/Views/Shared/_Layout.cshtml”呈现:“Scripts”. 报错内容如下: 解决办法如下: 1.在_Layout.cshtml布局body内 ...
- oop实现方法与属性继承
<script> /*父类 Person*/ function Person(name,age){ this.name=name; this.age=age; } Person.proto ...
- Android开发环境搭建简介
Android的开发工具,可以使用Eclipse,Idea,Android Studio,其中Eclipse是开源中国大部分使用的IDE,Idea是号称最好用的开发工具,有很多用处,Android S ...
- C# - Excel - Microsoft Access 数据库引擎找不到对象
我几乎要无语了,疯掉了,以为是office本身的问题,换了好多次office2007,安装又不顺利,换到了office2010,想想大部分应该兼容2007,所以用着office2010了. 甚至差点要 ...
- 重装eclipse要做的事(二)---设置工作空间默认编码
在Eclipse的开发使用中,我们经常使用的是UTF-8,但是刚刚安装的或者是导入的项目是其他编码的默认是GBK的,这就造成我们的项目乱码,一些中文解析无法查看,对我们的开发造成不便. 我使用的是My ...
- C++面试题:++i和i++哪个效率高?
1.当变量i的数据类型是c++语言默认提供的类型的话,他们的效率是一样的. 从其汇编执行的条数是一样的,所以其执行效率是一样的(有兴趣可以用gdb查看汇编代码) 2.我们自定的数据类型,++i效率高 ...
- GitHub——如何更新已经fork的代码
github上有个很方便的功能叫fork,将别人的工程一键复制到自己账号下.这个功能很方便,但有点不足的是,当源项目更新后,你fork的分支并不会一起更新,需要自己手动去更新.下面记录下网上找到的更新 ...
- 利用Python读取json数据并求数据平均值
要做的事情:一共十二个月的json数据(即12个json文件),json数据的一个单元如下所示.读取这些数据,并求取各个(100多个)城市年.季度平均值. { "time_point&quo ...
- 内联汇编和JMP到内联函数注意事项
对于jmp类型的hook, 如果自己的过程没有使用_declspec(naked),那么系统会自动给添加一些额外的代码,控制堆栈平衡,但是这些额外的代码会破坏被hook函数的堆栈. 对于call类型的 ...
- Hive笔记--配置以及遇到的问题
ubuntu安装mysql http://www.2cto.com/database/201401/273423.html Hive安装: http://www.aboutyun.com/forum ...