由于前段时间对java.net.URLConnection和org.apache.http.impl.client.HttpClients发送HTTP请求有所接触,发现在使用过程中碰到一些不一样的地方,特简单记录下来,以免忘记。
如果要说它们的区别,其实用过的人都知道,Java有原生的API可用于发送HTTP请求,即java.net.URL、java.net.URLConnection,这些API很好用、很常用,但不够简便;所以,才流行有许多Java HTTP请求的框架,如Apache的HttpClient。由此可见,Apache的HttpClient使用简便。
但我今天主要要说说我在使用过程中遇到的——java.net.URLConnection是请求间隔小于等于5秒,则不会新建TCP连接;如请求间隔大于5秒,则每次请求才会新建TCP连接,而Apache HttpClient在任何情况下都会新建TCP连接的问题现象及分析过程。
一.现象
为了证明这点,我特意新建了一个小工程(如下所示),向我本地的Web Application发送请求:
其中HttpRequestor.java就是从通过java.net.URLConnection发送HTTP请求中拷过来的。
ApacheClient.java
package com.bijian.study.http; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ApacheClient { private static final Logger logger = LoggerFactory.getLogger(ApacheClient.class); public static void httpRequest() throws Exception { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet("http://10.38.67.108:8080/SpringMVC/greeting"); HttpResponse response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); String html = EntityUtils.toString(entity); httpclient.close(); logger.info(html.replaceAll("\r\n", "")); } }
JavaHttpClient.java
package com.bijian.study.http; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.bijian.study.http.urlconnection.HttpRequestor; public class JavaHttpClient { private static final Logger logger = LoggerFactory.getLogger(JavaHttpClient.class); public static void httpRequest() throws Exception { /* Post Request */ //Map<String, String> dataMap = new HashMap<String, String>(); //dataMap.put("name", "zhangshan"); //String html = new HttpRequestor().doPost("http://10.38.67.108:8080/SpringMVC/greeting", dataMap); /* Get Request */ String html = new HttpRequestor().doGet("http://10.38.67.108:8080/SpringMVC/greeting?name=zhangshan"); logger.info(html.replaceAll("\r\n", "")); } }
MulThreadProcessClient.java
package com.bijian.study.client; import com.bijian.study.http.ApacheClient; import com.bijian.study.http.JavaHttpClient; public class MulThreadProcessClient implements Runnable { public void run() { try { //Apache HttpClient //ApacheClient.httpRequest(); //URLConnection HttpClient JavaHttpClient.httpRequest(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { while(true) { MulThreadProcessClient r = new MulThreadProcessClient(); Thread t = new Thread(r); t.start(); try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
由于我是在Windows下进行开发的,因此采用wireshark抓包分析的,而非Linux下非常著名的tcpdump命令。
如果是ApacheClient.httpRequest(),不管每发送一次请求休眠多少时间,每次请求都会有TCP三次握手(关于具体查看TCP三次握手请参看:http://bijian1013.iteye.com/blog/2299901),即都会重新建立连接,如下所示。
而如果是JavaHttpClient.httpRequest(),休眠时间小于等于5秒,则没有TCP的三次握手,请求间隔大于5秒,则每次请求也有TCP的三次握手过程。如下所示:
休眠时间小于等于5秒,无TCP的三次握手过程:
休眠时间大于5秒,有TCP的三次握手过程:
二.分析
1.Apache HttpClient的调用逻辑分析
1)HttpResponse response = httpclient.execute(httpget);
2)org.apache.http.impl.client.CloseableHttpClient的execute方法
3)org.apache.http.impl.client.InternalHttpClient的doExecute方法
4)org.apache.http.impl.execchain.MainClientExec的execute方法
5)org.apache.http.impl.execchain.MainClientExec的establishRoute方法
6)org.apache.http.impl.conn.BasicHttpClientConnectionManager的connect方法
7)org.apache.http.impl.conn.DefaultHttpClientConnectionOperator的connect方法
从上面的源代码来看,每次连接都会新建Socket连接。
二.HttpURLConnection的调用逻辑分析
1)com.bijian.study.http.urlconnection.HttpRequestor的doGet方法
2)sun.net.www.protocol.http.HttpURLConnection的getInputStream方法
2.1)sun.net.www.protocol.http.HttpURLConnection的connect方法
2.1.1)sun.net.www.protocol.http.HttpURLConnection的plainConnect方法
2.1.2)sun.net.www.protocol.http.HttpURLConnection的getNewHttpClient方法
2.1.2.1)sun.net.www.http.HttpClient的New方法
2.1.2.2)sun.net.NetworkClient的openServer方法
2.2)sun.net.www.http.HttpClient的parseHTTP方法
sun.net.www.http.HttpClient的parseHTTPHeader方法
2.3)sun.net.www.http.HttpClient的finished方法
2.3.1)sun.net.www.http.HttpClient的putInKeepAliveCache方法
2.3.2)sun.net.www.http.KeepAliveCache的put方法
也可以参看http://stackoverflow.com/questions/4767553/safe-use-of-httpurlconnection的如下内容。
于是我修改我的测试代码,增加System.setProperty("http.keepAlive", "false"),如下所示:
将休眠时间改成远小于5秒,测试发现每次请求也都会有TCP的三次握手过程,如下所示。
PS:
1.Wireshark的Filter内容:(http or tcp) and ip.src == 10.38.67.108 and ip.dst == 10.38.67.108 and tcp.port == 8080,这里我本机的IP地址是10.38.67.108。
2.请求的URL要写IP地址,不要写localhost,写localhost用Wireshark将抓不到包。如果要抓本地包,请查看wireshark如何抓取本机包。
3.由于我把本机既作为客户端又作为服务器端来调试代码,使得本机自己和自己通信。但是,这样wireshark是无法抓取到数据包的,需要通过如下简单的设置才可以,具体方法如下(详细及另外的方法请参看:wireshark如何抓取本机包):
①:以管理员身份运行cmd
②:route add 本机ip mask 255.255.255.255 网关ip
此时再利用wireshark进行抓包便可以抓到本机自己同自己的通信包。
4.Web Application应用的工程请直接到http://bijian1013.iteye.com/blog/2299764获取,测试验证工程请见附件TestHttpClient.zip。
相关推荐
在Java编程中,`java.net.URLConnection`是用于与各种Internet协议进行通信的抽象类,而HTTP(超文本传输协议)是最常见的应用之一。本文将深入探讨如何利用URLConnection类发送HTTP请求,理解其工作原理,并提供...
以下是如何利用`java.net.URLConnection`发送HTTP请求的详细步骤: 1. **创建URL对象**: 首先,你需要创建一个`java.net.URL`对象,它代表了你要访问的网络资源的地址。例如: ```java URL url = new URL(...
总结来说,虽然Java原生的`URLConnection`类相比第三方库(如Apache HttpClient或OkHttp)在某些情况下显得较为繁琐,但它具有良好的兼容性和无需额外依赖的优点。对于简单的HTTP请求,`URLConnection`完全能够胜任...
`java.net.URLConnection`则是`URL`的子接口,它提供了与资源进行交互的方法,如打开连接、读取数据、设置请求头等。在“java.net.URL测试代码”的场景中,我们通常会用到这两个类来实现网络编程中的跨域请求,并...
本文将详细介绍两种简单的方法来实现这一目标:使用`java.net.URLConnection`和`org.apache.http.client.HttpClient`。 首先,我们来看`URLConnection`的实现。`URLConnection`是Java内置的HTTP客户端,它提供了一...
在Java编程语言中,发送HTTP请求是常见的网络通信任务,主要用到的是`java.net.URL`和`java.net.HttpURLConnection`这两个核心类。本篇将详细介绍如何使用Java原生API实现简单的HTTP请求。 首先,我们需要了解HTTP...
3. `HttpClient`(Java 11+):从Java 11开始,内置了`java.net.http.HttpClient`,提供了一个现代、异步、高性能的API来处理HTTP请求。它支持同步和异步操作,简化了网络请求的编写。 ```java HttpClient client =...
通过以上内容我们可以看到,在Android平台上开发网络应用时,开发者可以根据实际需求选择使用标准Java接口`java.net.*`或者更加强大的Apache HttpClient。这些接口不仅提供了基础的HTTP通信能力,还支持诸如HTTPS、...
Java标准库提供了`java.net.HttpURLConnection`来发送HTTP请求,但实际开发中,我们常常会使用第三方库,如Apache HttpClient或OkHttp,它们提供了更强大的功能和易用性。 七、HTTPS安全通信 在处理敏感数据时,...
在Java中,访问网络资源是通过标准的Java API实现的,其中`java.net.URL`类和`java.net.URLConnection`类扮演了核心角色。本文将深入探讨这两个类以及如何使用它们来实现Java与服务器之间的数据交互。 首先,`java...
此外,如果你需要处理更复杂的网络请求,例如POST请求或者添加HTTP头,可以使用Apache HttpClient库或Java 7引入的`java.net.HttpURLConnection`。对于JSON或XML数据的解析,还可以使用Jackson或Gson库。 总的来说...
在Java编程语言中,HTTP下载是一项常见的任务,特别是在开发Web应用...此外,现代的Java库,如Apache HttpClient或OkHttp,提供了更强大、更易用的HTTP客户端功能,可以替代原生的`java.net`包,提升下载效率和稳定性。
对于更复杂的HTTP操作,如POST请求、Cookie管理等,可以利用Apache HttpClient或Java 7以后引入的`java.net.http.HttpClient`。 HTTPS(安全套接层超文本传输协议)是在HTTP基础上增加了SSL/TLS协议,用于加密通信...
import java.net.URLConnection; import java.net.HttpURLConnection; public class NetworkExample { public static void main(String[] args) throws Exception { // 创建一个URL对象 URL url = new URL(...
这个类继承自`java.net.URLConnection`,提供了HTTP特定的功能,如设置请求方法(GET、POST等),处理响应代码,以及设置和获取请求头。 创建一个简单的HTTP客户端程序,需要以下步骤: 1. **建立连接**:通过URL...
Java中可以通过`java.net.URL`和`java.net.URLConnection`类来实现GET请求。 2. **POST请求**:向服务器发送数据,常用于提交表单或者上传文件。可以使用`HttpURLConnection`或Apache HttpClient API来创建POST请求...
`java.net.URL`和`java.net.URLConnection`可以用来访问FTP服务器,而`javax.mail`包提供了发送电子邮件的功能。 网络编程中,异常处理非常重要。例如,连接超时、网络中断等问题需要通过捕获和处理`IOException`...