Http
Http协议是无状态的协议,每一次请求都是相互独立的,因此,最开始的设计是,每个htt请求都会打开一个 tcp socket 连接,当交互完毕后关闭这个连接。HTTP协议是全双工协议,所以建立连接与断开连接是要经过三次握手与四次挥手,显然,在这种设计 中,每次发送HTTP请求都会消耗额外资源时间,即连接的建立与销毁。
所以,持久连接的方式进行socket连接复用,是比较好的方式。
在串行连接中,每次交互都要打开关闭连接
在持久连接中,第一次交互打开连接,交互结束后连接并不关闭,复用给下一次交互,直到全部交互完毕,关闭连接,这样就省去了每次建立连接的过程。
Http连接池
1、降低延迟:如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手),如果采用连接池则减少了这部分时间损耗,别小看这几次握手,据说,基本上3倍的时间延迟
2、支持更大的并发:如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接(量变产生质变)
遇到的问题:有大量的TIME_WAIT,一边关闭连接,一边又请求打开连接,之前的没有关闭完成,没有释放完,端口被用完,没有可用端口,死循环,服务被压死。
出现:Cannot assign requested address
由于客户端频繁的连服务器,由于每次连接都在很短的时间内结束,导致很多的TIME_WAIT,以至于用光了可用的端 口号,所以新的连接没办法绑定端口,即“Cannot assign requested address”。是客户端的问题不是服务器端的问题。通过netstat,的确看到很多TIME_WAIT状态的连接。
client端频繁建立连接,而端口释放较慢,导致建立新连接时无可用端口。
HTTP连接池的设置
每个线程持有一个连接,并复用。
private CloseableHttpClient httpClient = HttpClients.custom().setMaxConnTotal(30).setMaxConnPerRoute(30).build();
public List<NumData> getHttpData(String an) throws Exception{
List<NumData> listJsonData = new ArrayList<>();
String url = "地址"+an;//url访问地址
HttpGet httpGet = new HttpGet(url);
String result = "";
JSONArray jsonArray = null;
CloseableHttpResponse response;
HttpEntity httpEntity = null;
try {
response = httpClient.execute(httpGet);
httpEntity = response.getEntity();
if (httpEntity != null) {
result = EntityUtils.toString(httpEntity, "utf-8");
}
try {
jsonArray = JSONArray.fromObject(result);
} catch (Exception e) {
return null;
}
for(int i=0; i<jsonArray.size(); i++){
NumData numData = new NumData();
JSONObject obj = (JSONObject) jsonArray.get(i);
Iterator it = obj.keys();
while (it.hasNext()) {
String key = it.next().toString();
if("an".equals(key)){
numData.setAn(obj.getString(key));
numData.setTARGET_SORT(i+1);
break;
}
}
listJsonData.add(numData);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (httpEntity != null) {
EntityUtils.consume(httpEntity);
}
}
return listJsonData;
}
public static void staticClose() throws IOException {
httpUtils.close();
}
setMaxConnTotal(30):设置最大连接数
setMaxConnPerRoute(30):设置每个路由默认连接数
EntityUtils对象是org.apache.http.util下的一个工具类,用官方的解释是为HttpEntity对象提供的静态帮助类,其常用的几个方法如下:
consume()方法;
consumeQuietly(HttpEntity)方法
toByteArray(final HttpEntity entity)方法
最主要的就是consume()这个方法,其功能就是关闭HttpEntity的流
对于实体的资源使用完之后要适当的回收资源,特别是对于流实体