UrlConnection鏈接和Socket鏈接的區別

關於UrlConnection鏈接和Socket鏈接的區別,只知道其中的原理以下:
抽象一點的說,Socket只是一個供上層調用的抽象接口,隱躲了傳輸層協議的細節。
urlconnection 基於Http協議,Http協議是應用層協議,對傳輸層Tcp協議進行了封裝,是無狀態協議,不須要你往考慮線程、同步、狀態治理等,html

內部是經過socket進行鏈接和收發數據的,不過通常在數據傳輸完成以後須要封閉socket鏈接。
直接使用Socket進行網絡通信得考慮線程治理、客戶狀態監控等,可是不用發送頭信息等,更省流量。java


並不知道咱們常常使用的URLConnection 內部是怎麼實現的,今天心血來潮以URL爲出發點來探個究竟。
如下面這段代碼爲出發點
URL url = new URL("http://zhoujianghai.iteye.com");
URLConnection conecttion = (URLConnection)url.openConnection();

根據java.net.URL源碼,一步步進行分析,
new URL("www.javaeye.com")會調用URL(URL context, String spec, URLStreamHandler handler),
此時context和handler是null。
url.openConnection()調用的是strmHandler.openConnection(this);
而strmHandler是URLStreamHandler接口的子類的實例。
抽象類 URLStreamHandler 是全部流協議處理程序的通用超類,能夠經過不一樣 protocol 的 URL 實例,產生 java.net.URLConnection 對象。
因爲context和handler是null,因此終極根據具體的協議調用URL類中的setupStreamHandler()方法對strmHandler進行初始化。

下面分析 setupStreamHandler()方法內的代碼。apache

?api

?網絡

[java] view plain copy
  1. String packageList = AccessController.doPrivileged(new PriviAction<String>(  
  2.                         "java.protocol.handler.pkgs"));  

?socket

?
首先經過java.protocol.handler.pkgs 來設置 URLStreamHandler 實現類的包路徑,SUN 的 JDK 內部實現類均是在 sun.net.www.protocol. 包下。
關於sun/net/www/protocol/http包下相關類的源碼,能夠訪問:http://www.docjar.org/docs/api/sun/net/www/protocol/http/package-index.htmlide


PriviAction 部分源碼:this

[java] view plain copy
  1. public PriviAction(String property) {  
  2.       action = GET_SYSTEM_PROPERTY;  
  3.     arg1 = property;  
  4.     }  
  5.   
  6. public T run() {  
  7.    switch (action) {  
  8.      case GET_SYSTEM_PROPERTY:  
  9.      return (T)System.getProperty((String) arg1, (String) arg2);  
  10.     case GET_SECURITY_PROPERTY:  
  11.      return (T)Security.getProperty((String) arg1);  
  12.      case GET_SECURITY_POLICY:  
  13.      return (T)Policy.getPolicy();  
  14.      case SET_ACCESSIBLE:  
  15.      ((AccessibleObject) arg1).setAccessible(true);  
  16.      }  
  17.      return null;  
  18.      }  
  19. PriviAction<T> 實現了 java.security.PrivilegedAction<T>接口,會執行run()方法。  
  20. 由action = GET_SYSTEM_PROPERTY;可知會執行代碼:  
[java] view plain copy
  1. (T)System.getProperty((String) arg1, (String) arg2);  
[java] view plain copy
  1. System.getProperty方法調用成員變量Properties props的getProperty(key, def)方法;  
  2. 因爲並未設置任何Properties,此處會返回默認值def。def的值是null。  
  3. 所以會繼續執行下面的代碼:  
[java] view plain copy
  1. String className = "org.apache.harmony.luni.internal.net.www.protocol." + protocol   
  2. ".Handler";   
  3.         try {  
  4.             strmHandler = (URLStreamHandler) Class.forName(className)  
  5.                     .newInstance();  
  6.         } catch (IllegalAccessException e) {  
  7.         } catch (InstantiationException e) {  
  8.         } catch (ClassNotFoundException e) {  
  9.         }  
  10. 此時protocol是http協議,從而根據協議 (protocol) 得到協議 URLStreamHandler 對象。  
  11. 因此此時經過反射機制建立org.apache.harmony.luni.internal.net.www.protocol.http.Handler類的實例。  
  12. 此時回到上面提到的 strmHandler.openConnection(this);  

將調用下面的Handler類的實例的openConnection(URL u)方法。url


@Overridespa

[java] view plain copy
  1. protected URLConnection openConnection(URL u) throws IOException {  
  2.     return new HttpURLConnectionImpl(u, getDefaultPort());  
  3. }  
  4.   
  5.   
  6. ected URLConnection openConnection(URL u, Proxy proxy)  
  7.         throws IOException {  
  8.     if (null == u || null == proxy) {  
  9.         throw new IllegalArgumentException(Messages.getString("luni.1B"));   
  10.     }  
  11.     return new HttpURLConnectionImpl(u, getDefaultPort(), proxy);  
  12. }  


此時會建立HttpURLConnectionImpl對象。HttpURLConnectionImpl是java.net.HttpURLConnection的子類。 該類有個成員變量

HttpConnection connection;這纔是咱們要找的,該類對Socket進行了封裝。


HttpConnection 部分源碼以下:


 private Socket socket;

[java] view plain copy
  1.          private SSLSocket sslSocket;  
  2.         
  3.          private InputStream inputStream;  
  4.           private OutputStream outputStream;  
  5.          private InputStream sslInputStream;  
  6.          private OutputStream sslOutputStream;  
  7.         
  8.          private HttpConfiguration config;  
  9.         
  10.           public HttpConnection(HttpConfiguration config, int connectTimeout) throws IOException {  
  11.               this.config = config;  
  12.              String hostName = config.getHostName();  
  13.              int hostPort = config.getHostPort();  
  14.               Proxy proxy = config.getProxy();  
  15.               if(proxy == null || proxy.type() == Proxy.Type.HTTP) {  
  16.                  socket = new Socket();  
  17.               } else {  
  18.                   socket = new Socket(proxy);  
  19.               }  
  20.               socket.connect(new InetSocketAddress(hostName, hostPort), connectTimeout);  
  21.           }  
  22.   
  23.   
  24. 如今UrlConnection鏈接和Socket鏈接的區別應該十分清楚了吧。  
  25. 使用UrlConnection比直接使用Socket要簡單的多,不用關心狀態和線程治理。  
  26. UrlConnection基於Http協議,只是進行了封裝,添加了一些額外規則(如頭信息),本質上也是創建TCP鏈接,利用Socket
  27. 實現鏈接和傳輸數據的,不過咱們通常每次請求完數據後都會實現finally方法,在該方法裏封閉鏈接。  

四周是相關類的源碼。
能夠往這個連接地址查找更多類的源碼:
http://www.docjar.com/projects/apache-harmony-6.0-src-r917296-snapshot-code.html

相關文章
相關標籤/搜索