关于HttpURLConnection的TCP连接

背景

在工作中,我被问及一个问题CXF的WebClient是如何通过连接发送请求的,到最后引申为HttpURLConnection的TCP连接的重用问题。

问题描述

在一个线程中,多个方法调用HttpURLConnection conn = (HttpURLConnection) url.openConnection() 建立一次TCP连接还是多次TCP连接?

具体点讲,如下代码中HttpClient有3个方法,每个都调用 HttpURLConnection conn = (HttpURLConnection) url.openConnection() ,那么一个线程调用method1, method2 然后method3, JDK会为这个线程创建多少个TCP连接?

package art.programming.net;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * see 
 * http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html
 * 
 * 
 * @author Alex Chen
 */
public class HttpClient {
	public static void main(String... args){
		try{
			final URL url = new URL("http://www.google.cn");
			HttpClient httpClient = new HttpClient();
			httpClient.method1(url);
			httpClient.method2(url);
			httpClient.method3(url);
			
			/**
			new Thread(){
				public void run(){
					HttpClient httpClient = new HttpClient();
					httpClient.method1(url);
					httpClient.method2(url);
					httpClient.method3(url);
				}
			}.start();
			**/
	
		}catch(Exception e){
			
		}
	}
	
	public  void method1(final URL url){
		try {
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("HEAD");
			int len = conn.getContentLength();
			System.out.println("内容长度: " + len);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public  void method2(final URL url){
		try {
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("HEAD");
			int len = conn.getContentLength();
			System.out.println("内容长度: " + len);
			//conn.disconnect();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public  void method3(final URL url){
		try {
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("HEAD");
			int len = conn.getContentLength();
			System.out.println("内容长度: " + len);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

从Wireshark抓到的数据包分析来看,答案是1个TCP连接。

Monitor

从上图,我观察到系统间建立连接之后(SYN,ACK)连续发送3个HTTP请求。所以即使是在不同的方法里面调用HttpURLConnection conn = (HttpURLConnection) url.openConnection() ;系统也只是创建一个连接。

那么,如果是2个线程会创建多少个连接呢?我把代码修改成如下,

package art.programming.net;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * see 
 * http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html
 * 
 * 
 * @author Alex Chen
 */
public class HttpClient {
	public static void main(String... args){
		try{
			final URL url = new URL("http://www.google.cn");
			new Thread(){
				public void run(){
					HttpClient httpClient = new HttpClient();
					httpClient.method1(url);
					httpClient.method2(url);
					httpClient.method3(url);
				}
			}.start();
			
			
			new Thread(){
				public void run(){
					HttpClient httpClient = new HttpClient();
					httpClient.method1(url);
					httpClient.method2(url);
					httpClient.method3(url);
				}
			}.start();
			
	
		}catch(Exception e){
			
		}
	}
	
	public  void method1(final URL url){
		try {
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("HEAD");
			int len = conn.getContentLength();
			System.out.println("内容长度: " + len);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public  void method2(final URL url){
		try {
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("HEAD");
			int len = conn.getContentLength();
			System.out.println("内容长度: " + len);
			//conn.disconnect();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public  void method3(final URL url){
		try {
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("HEAD");
			int len = conn.getContentLength();
			System.out.println("内容长度: " + len);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

观察到2个连接被建立(两个SYN,ACK),处理6次HTTP请求。同时观察到TCP连接没有被关闭(没有FIN标志位出现)。

Monitor2

结论

URL.openConnection并不是每次都会创建一个TCP连接。

原文地址:https://www.cnblogs.com/cando/p/2669343.html