1. 程式人生 > >UrlConnection連接和Socket連接的區別

UrlConnection連接和Socket連接的區別

反射機制 leg 代碼 key 請求 connect protoc sdn hand

關於UrlConnection連接和Socket連接的區別,只知道其中的原理如下:
抽象一點的說,Socket只是一個供上層調用的抽象接口,隱躲了傳輸層協議的細節。
urlconnection 基於Http協議,Http協議是應用層協議,對傳輸層Tcp協議進行了封裝,是無狀態協議,不需要你往考慮線程、同步、狀態治理等,內部是通過socket進行連接和收發數據的,不過一般在數據傳輸完成之後需要封閉socket連接。
直接使用Socket進行網絡通訊得考慮線程治理、客戶狀態監控等,但是不用發送頭信息等,更省流量。


並不知道我們經常使用的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()方法內的代碼。

?

?

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

?

?
首先通過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.html


PriviAction 部分源碼:

[java] view plain copy
  1. public PriviAction(String property) {
  2. action = GET_SYSTEM_PROPERTY;
  3. arg1 = property;
  4. }
  5. public T run() {
  6. switch (action) {
  7. case GET_SYSTEM_PROPERTY:
  8. return (T)System.getProperty((String) arg1, (String) arg2);
  9. case GET_SECURITY_PROPERTY:
  10. return (T)Security.getProperty((String) arg1);
  11. case GET_SECURITY_POLICY:
  12. return (T)Policy.getPolicy();
  13. case SET_ACCESSIBLE:
  14. ((AccessibleObject) arg1).setAccessible(true);
  15. }
  16. return null;
  17. }
  18. PriviAction<T> 實現了 java.security.PrivilegedAction<T>接口,會執行run()方法。
  19. 由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)方法。


@Override

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


此時會創建HttpURLConnectionImpl對象。HttpURLConnectionImpl是java.net.HttpURLConnection的子類。 該類有個成員變量HttpConnection connection;
這才是我們要找的,該類對Socket進行了封裝。


HttpConnection 部分源碼如下:


private Socket socket;

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

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

UrlConnection連接和Socket連接的區別