`

java.net.URLConnection发送HTTP请求与通过Apache HttpClient发送HTTP请求比较

阅读更多

        由于前段时间对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。

  • 大小: 11.5 KB
  • 大小: 19.7 KB
  • 大小: 35.8 KB
  • 大小: 42.4 KB
  • 大小: 30.1 KB
  • 大小: 37.7 KB
  • 大小: 75.8 KB
  • 大小: 23.4 KB
  • 大小: 23.9 KB
  • 大小: 23.2 KB
  • 大小: 48.9 KB
  • 大小: 113.4 KB
  • 大小: 18.9 KB
  • 大小: 27 KB
分享到:
评论

相关推荐

    通过java.net.URLConnection发送HTTP请求

    在Java编程中,`java.net.URLConnection`是用于与各种Internet协议进行通信的抽象类,而HTTP(超文本传输协议)是最常见的应用之一。本文将深入探讨如何利用URLConnection类发送HTTP请求,理解其工作原理,并提供...

    java如何利用java.net.URLConnection发送HTTP.docx

    以下是如何利用`java.net.URLConnection`发送HTTP请求的详细步骤: 1. **创建URL对象**: 首先,你需要创建一个`java.net.URL`对象,它代表了你要访问的网络资源的地址。例如: ```java URL url = new URL(...

    java利用java.net.URLConnection发送HTTP请求的方法详解

    总结来说,虽然Java原生的`URLConnection`类相比第三方库(如Apache HttpClient或OkHttp)在某些情况下显得较为繁琐,但它具有良好的兼容性和无需额外依赖的优点。对于简单的HTTP请求,`URLConnection`完全能够胜任...

    java.net.URL测试代码

    `java.net.URLConnection`则是`URL`的子接口,它提供了与资源进行交互的方法,如打开连接、读取数据、设置请求头等。在“java.net.URL测试代码”的场景中,我们通常会用到这两个类来实现网络编程中的跨域请求,并...

    详解Java两种方式简单实现:爬取网页并且保存

    本文将详细介绍两种简单的方法来实现这一目标:使用`java.net.URLConnection`和`org.apache.http.client.HttpClient`。 首先,我们来看`URLConnection`的实现。`URLConnection`是Java内置的HTTP客户端,它提供了一...

    使用JAVA原生实现简单的HTTP请求

    在Java编程语言中,发送HTTP请求是常见的网络通信任务,主要用到的是`java.net.URL`和`java.net.HttpURLConnection`这两个核心类。本篇将详细介绍如何使用Java原生API实现简单的HTTP请求。 首先,我们需要了解HTTP...

    向URL发送请求

    3. `HttpClient`(Java 11+):从Java 11开始,内置了`java.net.http.HttpClient`,提供了一个现代、异步、高性能的API来处理HTTP请求。它支持同步和异步操作,简化了网络请求的编写。 ```java HttpClient client =...

    Android网络开发

    通过以上内容我们可以看到,在Android平台上开发网络应用时,开发者可以根据实际需求选择使用标准Java接口`java.net.*`或者更加强大的Apache HttpClient。这些接口不仅提供了基础的HTTP通信能力,还支持诸如HTTPS、...

    Java-Java网络编程教程

    Java标准库提供了`java.net.HttpURLConnection`来发送HTTP请求,但实际开发中,我们常常会使用第三方库,如Apache HttpClient或OkHttp,它们提供了更强大的功能和易用性。 七、HTTPS安全通信 在处理敏感数据时,...

    java访问网络资源

    在Java中,访问网络资源是通过标准的Java API实现的,其中`java.net.URL`类和`java.net.URLConnection`类扮演了核心角色。本文将深入探讨这两个类以及如何使用它们来实现Java与服务器之间的数据交互。 首先,`java...

    Java从网络取得图像源码

    此外,如果你需要处理更复杂的网络请求,例如POST请求或者添加HTTP头,可以使用Apache HttpClient库或Java 7引入的`java.net.HttpURLConnection`。对于JSON或XML数据的解析,还可以使用Jackson或Gson库。 总的来说...

    java写的http下载

    在Java编程语言中,HTTP下载是一项常见的任务,特别是在开发Web应用...此外,现代的Java库,如Apache HttpClient或OkHttp,提供了更强大、更易用的HTTP客户端功能,可以替代原生的`java.net`包,提升下载效率和稳定性。

    java网络编程rar

    对于更复杂的HTTP操作,如POST请求、Cookie管理等,可以利用Apache HttpClient或Java 7以后引入的`java.net.http.HttpClient`。 HTTPS(安全套接层超文本传输协议)是在HTTP基础上增加了SSL/TLS协议,用于加密通信...

    Android网络开发详解

    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-URL.rar_java URL HTTP

    这个类继承自`java.net.URLConnection`,提供了HTTP特定的功能,如设置请求方法(GET、POST等),处理响应代码,以及设置和获取请求头。 创建一个简单的HTTP客户端程序,需要以下步骤: 1. **建立连接**:通过URL...

    Java Http通信测试代码

    Java中可以通过`java.net.URL`和`java.net.URLConnection`类来实现GET请求。 2. **POST请求**:向服务器发送数据,常用于提交表单或者上传文件。可以使用`HttpURLConnection`或Apache HttpClient API来创建POST请求...

    java基础网络编程

    `java.net.URL`和`java.net.URLConnection`可以用来访问FTP服务器,而`javax.mail`包提供了发送电子邮件的功能。 网络编程中,异常处理非常重要。例如,连接超时、网络中断等问题需要通过捕获和处理`IOException`...

Global site tag (gtag.js) - Google Analytics