zoukankan      html  css  js  c++  java
  • 关于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连接。

  • 相关阅读:
    c++ builder 获取命令行参数
    c++ builder 只允许程序运行一个实例
    jQuery学习笔记(三)
    jQuery学习笔记(二)
    jQuery实现一个弹出登陆层的效果
    jQuery学习笔记(一)
    20117月
    201112学习
    21125
    211211
  • 原文地址:https://www.cnblogs.com/cando/p/2669343.html
Copyright © 2011-2022 走看看