Socket编程笔记

android中的socket连接HttpURLConnection来实现的。而HttpClient是对HttpURLConnection做了一层封装,HttpClient6.0之后被废弃了,推荐用HttpURLConnection。而HttpURLConnection继承于HttpConnection,两者都是抽象类,想了解其中的实现原理,就要深入的剖析一下代码,但是其中一些关键的方法如connect()方法却是抽象的,所以需要找到它的实现类。

首先,是找到connect()的实现,最可能的是在URL类中找线索,因为是在url中获取的

URL url = new URL(httpUrl);//此处有异常抛出
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();

然而,URL中却显示streamHandler中取得的

public URLConnection openConnection() throws IOException {
    return streamHandler.openConnection(this);
}

而streamHandler这个实例所属的对象实现的方法仍然是抽象的

protected abstract URLConnection openConnection(URL u) throws IOException;

也就是说单独知道这个出处还不够,还需要知道streamHandler是在什么时候被赋值的,这时候可以注意到URL中有URLStreamHandlerFactory streamHandlerFactory的工厂声明,点击去发现还是抽象的(晕),然后顺着streamHandlerFactory就找到了下面的方法,是对streamHandler赋值的关键

 void setupStreamHandler() {
    // Check for a cached (previously looked up) handler for
    // the requested protocol.
    streamHandler = streamHandlers.get(protocol);
    if (streamHandler != null) {
        return;
    }

    // If there is a stream handler factory, then attempt to
    // use it to create the handler.
    if (streamHandlerFactory != null) {
        streamHandler = streamHandlerFactory.createURLStreamHandler(protocol);
        if (streamHandler != null) {
            streamHandlers.put(protocol, streamHandler);
            return;
        }
    }

    // Check if there is a list of packages which can provide handlers.
    // If so, then walk this list looking for an applicable one.
    String packageList = System.getProperty("java.protocol.handler.pkgs");
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    if (packageList != null && contextClassLoader != null) {
        for (String packageName : packageList.split("\\|")) {
            String className = packageName + "." + protocol + ".Handler";
            try {
                Class<?> c = contextClassLoader.loadClass(className);
                streamHandler = (URLStreamHandler) c.newInstance();
                if (streamHandler != null) {
                    streamHandlers.put(protocol, streamHandler);
                }
                return;
            } catch (IllegalAccessException ignored) {
            } catch (InstantiationException ignored) {
            } catch (ClassNotFoundException ignored) {
            }
        }
    }

    // Fall back to a built-in stream handler if the user didn't supply one
    if (protocol.equals("file")) {
        streamHandler = new FileHandler();
    } else if (protocol.equals("ftp")) {
        streamHandler = new FtpHandler();
    } else if (protocol.equals("http")) {
        try {
            String name = "com.android.okhttp.HttpHandler";
            streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    } else if (protocol.equals("https")) {
        try {
            String name = "com.android.okhttp.HttpsHandler";
            streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    } else if (protocol.equals("jar")) {
        streamHandler = new JarHandler();
    }
    if (streamHandler != null) {
        streamHandlers.put(protocol, streamHandler);
    }
}

看注释区分,总共分为4个部分

第一部分

 streamHandler = streamHandlers.get(protocol);
    if (streamHandler != null) {
        return;
    }

是取缓存的streamHandler实例,如果已经存在了,就不会往下执行了。

第二部分

if (streamHandlerFactory != null) {
        streamHandler = streamHandlerFactory.createURLStreamHandler(protocol);
        if (streamHandler != null) {
            streamHandlers.put(protocol, streamHandler);
            return;
        }
    }

明显用到了工厂,所以需要知道工厂的出处,是这里:

/**
 * Sets the stream handler factory for this VM.
 *
 * @throws Error if a URLStreamHandlerFactory has already been installed
 *     for the current VM.
 */
public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory factory) {
    if (streamHandlerFactory != null) {
        throw new Error("Factory already set");
    }
    streamHandlers.clear();
    streamHandlerFactory = factory;
}

得了,这个是公共的设置方法:Sets the stream handler factory for this VM顿时感觉好高大上,总之,不通。

第三部分

在系统属性指定的包中寻找相应的URLStreamHandler处理类,因为没怎么用过这种方法,值得注意,不过不是这里的重点

String packageList = System.getProperty("java.protocol.handler.pkgs");
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    if (packageList != null && contextClassLoader != null) {
        for (String packageName : packageList.split("\\|")) {
            String className = packageName + "." + protocol + ".Handler";
            try {
                Class<?> c = contextClassLoader.loadClass(className);
                streamHandler = (URLStreamHandler) c.newInstance();
                if (streamHandler != null) {
                    streamHandlers.put(protocol, streamHandler);
                }
                return;
            } catch (IllegalAccessException ignored) {
            } catch (InstantiationException ignored) {
            } catch (ClassNotFoundException ignored) {
            }
        }
    }

第四部分

再不成只能做最后的挣扎了

if (protocol.equals("file")) {
        streamHandler = new FileHandler();
    } else if (protocol.equals("ftp")) {
        streamHandler = new FtpHandler();
    } else if (protocol.equals("http")) {
        try {
            String name = "com.android.okhttp.HttpHandler";
            streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    } else if (protocol.equals("https")) {
        try {
            String name = "com.android.okhttp.HttpsHandler";
            streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    } else if (protocol.equals("jar")) {
        streamHandler = new JarHandler();
    }
    if (streamHandler != null) {
        streamHandlers.put(protocol, streamHandler);
    }

其中https依然是在特定包com.android.okhttp.HttpsHandler中找
而其他的则是直接new一个对象,这些对象的导入

import libcore.net.url.FileHandler;
import libcore.net.url.FtpHandler;
import libcore.net.url.JarHandler;

在androidstudio中显示的是灰色的,表示没有没有提供相关源码,至此,线索全断了,不过通过这些查找也并非没有收获。

一直以来找的URLStreamHandler streamHandler其实是一个协议流处理器,每一个
对应一个URLHttpConnection,至于实现它们的源码,限于sdk中源码包没有所以没看到,不过却找到了出处,网上查了一下知道了其中实现也是通过Socket,大体的关系总是理清了。

总结:

1.URLHttpConnection和URLHttpsConnection都继承了URLConnection都是基于应用层对http或https协议的封装,里面通信还是用的socket

2.URLConnection里面调用的Socket是传输层对应用层提供的抽象接口,是下层黑箱的一个门面,其中包括的协议有传输层的TCP协议和UDP协议,以及网络层的IP协议。当然也可以直接用socket通信,可以在应用层通过socket来架构网络框架,但是需要考虑多线程,以及状态监控(其实用URLConnection也要自己写多线程)等因素,更省流量以及更可控,但是如果要用到http等应用层协议,还是用URLConnection方便些。

3.每个URLConnection都有一个相对应的URLStreamHandler实例用来处理协议,URL类中还有关于file,ftp,jar对应类型的URLStreamHandler应该也是一些协议的封装的处理器,也就是说每一种协议需要对应一种处理模型。

最后,温习一下网络模型:

应用层-应用层,表示层,会话层

传输层-传输层

网际互联层-网络层

网络接入层-数据链路层,物理层

Loading Disqus comments...
Table of Contents