欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JDK8 网络Net包研究(一)

程序员文章站 2022-07-12 14:49:54
...

网络基础

     1)国际标准化组织OSI[开放式系统互联模型]七层模型

     2)TCP/IP协议[]四层模型

     3)TCP/IP协议组一组包括TCP协议和IP协议,UDP协议、ICMP协议和其他一些协议的协议组

网络层

    IP协议->网络互连协议   用途:将多个包在网络中联系起来,传输数据包(不可靠传输),最基本功能就是寻址和分段功能,不提供端到端,路由到路由的确认,不提供重发和流量控制。是计算机网络能狗相互通信的基本规则。出错则像ICMP报告,ICMP在IP模块中实现

    ICMP协议,   用途:面向无连接协议,用于传输错误报告控制信息(控制信息是指网络不通畅,主机是否到达,路由是否可用的这些网络本身的消息,不涉及用户传输的数据)

      ARP协议->地址解析协议 用途:根据IP地址获取物理地址的协议(即MAC地址)。在同一子网内通过ARP协议可以实现数据包的互相传递。不在一个子网内则无法获得MAC地址,只有通过网关去处理。

      RARP协议->反转地址协议 用途:和ARP协议相反,将主机的物理地址转换成IP地址。

      BOOTP协议->引导程序协议 用途:用于无盘工作站的局域网中,可以无盘工作站从一个中心服务器上获得IP地址。

传输层:

    TCP协议->传输控制协议   用途:主要用于网间传输的协议,分割处理报文并把结果包传到IP层,并接收处理IP曾传到的数据包。

     UDP协议->用户数据协议  用途:主要用于需要在计算器之间传输数据的应用,将网络数据流浪压缩成数据包。

应用层:

    NET协议->网络地址转换协议 用途:实现内网IP地址和公网地址之间的相互转换。将大量的内网IP转换成一个或者少量的公网IP

    FTP协议->文件传输协议 用途:通过FTP协议在FTP客户端访问FTP服务端,默认使用20和21端口,20用于传输数据,21用于传输控制信息。

    HTTP协议->超文本传输协议 用途:是用于从WWW服务器传输超文本到本地浏览器的传输协议。是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。

  TELNET协议 用途:是Internet远程登陆服务的标准协议和主要方式,为用户提供了在本地计算机上完成远程主机工作的能力。

   SMTP协议->简单邮件传输协议  用途:控制邮件传输的规则,以及邮件的中转方式。

   DNS协议 用途:定义域名规则,将域名和IP相互映射

InetAddress部分

InetAddress类用于封装一个数据式的网络IP地址和域名。

public class InetAddress{
    #获取InetAddress对象的5个成员方法:
    public static InetAddress getByAddress(String host, byte[] addr)
    public static InetAddress getByName(String host)
    public static InetAddress[] getAllByName(String host)
    public static InetAddress getByAddress(byte[] addr)
    public static InetAddress getByAddress(byte[] addr)

    #获取主机名等地址信息的6个成员方法:
    public String getHostName()
    public byte[] getAddress()
    public String getHostAddress() 
    public boolean isMulticastAddress()
    public boolean isLoopbackAddress() 
    public String getCanonicalHostName()

    #定义static class InetAddressHolder内部类
    static class InetAddressHolder{......}

    #InetAddress Constructor 
       final transient InetAddressHolder holder;
        InetAddress() {
            holder = new InetAddressHolder();
    }

    #将网络库加载到运行时,并执行初始化
    static transient boolean preferIPv6Address = false;//IPv4Address
    static {
            preferIPv6Address = java.security.AccessController.doPrivileged(
            new GetBooleanAction("java.net.preferIPv6Addresses")).booleanValue();
            AccessController.doPrivileged(    
                new java.security.PrivilegedAction<Void>() {
                    public Void run() { System.loadLibrary("net"); return null; }
            });
            init();//native method
    }

    #deserialized InetAddress object with Inet4Address
    private Object readResolve() throws ObjectStreamException {
        return new Inet4Address(holder().getHostName(),holder().getAddress());
    }
    #定义InetAddress[]和InetAddressImpl,InetAddressImpl接口被Inet4AddressImpl、Inet6AddressImpl实现
    static InetAddress[]    unknown_array; // put THIS in cache
    static InetAddressImpl  impl;
    private static List<NameService> nameServices = null;#存储the name service provider
    
    #创建InetAddressImpl、NameService
     static {
        // create the impl,见InetAddressImplFactory
        impl = InetAddressImplFactory.create();
        // get name service if provided and requested
        String provider = null;;
        String propPrefix = "sun.net.spi.nameservice.provider.";
        int n = 1;
        nameServices = new ArrayList<NameService>();
        provider = AccessController.doPrivileged(
                new GetPropertyAction(propPrefix + n));
        while (provider != null) {
            NameService ns = createNSProvider(provider);
            if (ns != null)
                nameServices.add(ns);

            n++;
            provider = AccessController.doPrivileged(
                    new GetPropertyAction(propPrefix + n));
        }

        // if not designate any name services provider,
        // create a default one
        if (nameServices.size() == 0) {
            NameService ns = createNSProvider("default");
            nameServices.add(ns);
        }
    }

    #内部类工厂模式
    class InetAddressImplFactory {
          static InetAddressImpl create() {
            return InetAddress.loadImpl(isIPv6Supported() ? "Inet6AddressImpl" : "Inet4AddressImpl");
         }
         static native boolean isIPv6Supported();
    }
    #装入并实例化一个底层的impl类
    static InetAddressImpl loadImpl(String implName) {
        Object impl = null;
        ......
        if (impl == null) {
            try {
                impl = Class.forName(implName).newInstance();
            } catch (Exception e) {
                throw new Error("System property impl.prefix incorrect");}
          }
        return (InetAddressImpl) impl;
    }

 

URL部分

   统一资源定位符,用来标识互联网上的资源,采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。

 

#构造函数

    public URL(String spec)

    public URL(URL context, String spec)

    public URL(String protocol, String host, String file)

    public URL(String protocol, String host, int port, String file)

  #重要成员方法

    public final InputStream openStream()

    public URLConnection openConnection()

socket部分

 Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换连接的一端称为一个socketSocket类代表流套按字连接两端中的任意一端,可以服务器或客户端两端使用。

 类设计关系图

JDK8 网络Net包研究(一)

1 Socket类

#定义Socket抽象类接口

SocketImpl impl;

#构造Socket(1个默认构造函数,3个带参构造函数,2个做费构造函数)

#默认构造函数,创建无连接Socket

public Socket()

#Creates a stream socket and connects it to the specified port  number on the named host

public Socket(String host, int port) {

  this(host != null ? new InetSocketAddress(host, port) :

     new InetSocketAddress(InetAddress.getByName(null), port),(SocketAddress) null, true);

}

#Creates a stream socket and connects it to the specified port  number at the specified IP address

public Socket(InetAddress address, int port)  {

  this(address != null ? new InetSocketAddress(address, port) : null,(SocketAddress) null, true);

}

#Creates a socket and connects it to the specified remote host on the specified remote port. The Socket will also bind() to the local address and port supplied

public Socket(String host, int port, InetAddress localAddr, int localPort) {

  this(host != null ? new InetSocketAddress(host, port) :

             new InetSocketAddress(InetAddress.getByName(null), port),

            new InetSocketAddress(localAddr, localPort), true);

}

#以上各构造函数中调用的this函数定义即为如下Socket方法

private Socket(SocketAddress address, SocketAddress localAddr, boolean stream)  {

        setImpl();

        // backward compatibility

        try {

            createImpl(stream);

            if (localAddr != null)

                bind(localAddr);

            connect(address);

        ...

 }


2 InetSocketAddress类

    提供了一个用于套接字绑定、连接或返回值的不可变对象,主要包括Socket Address对象信息,即主机名-hostname StringIP地址-addr InetAddress,端口-port int三个属性。

public class InetSocketAddress extends SocketAddress{...}

JDK8 网络Net包研究(一)

3 Socket分析

Socket客户端Socket类分析

说明:以 public Socket(String host, int port)为入口点

3.1)初始化InetSocketAddress对象,并递归调用this方法

public Socket(String host, int port) {

      this(host != null ? new InetSocketAddress(host, port) :

             new InetSocketAddress(InetAddress.getByName(null), port),

             (SocketAddress) null, true);

}

3.2)this方法,参数stream = true

private Socket(SocketAddress address, SocketAddress localAddr,boolean stream) throws IOException {

        setImpl();//设置默认的抽象类SocketImpl接口对象

        // backward compatibility

        if (address == null)   throw new NullPointerException();

        try {

//Creates the socket implementation,stream:true TCP socket,false:UDP,最终代码调用跟踪到native int socket0方法

            createImpl(stream);

           if (localAddr != null)

                //Binds this socket to the specified local IP address and port number,最终代码调用跟踪到native void bind0方法

                 bind(localAddr);

            connect(address);

            ....

        }

3.3)connect(address), 跟踪核心过程方法->

    /**

     * Connects this socket to the server with a specified timeout value.

     * @param   endpoint the {@code SocketAddress}

     * @param   timeout  the timeout value to be used in milliseconds.

     */

    public void connect(SocketAddress endpoint, int timeout) {

        ...

        InetSocketAddress epoint = (InetSocketAddress) endpoint;

        InetAddress addr = epoint.getAddress ();

        int port = epoint.getPort();

        checkAddress(addr, "connect");

        ...

        if (epoint.isUnresolved())

             impl.connect(addr.getHostName(), port);

        else

             impl.connect(addr, port);

         ...

     }

 3.4)impl.connect(addr, port), 跟踪核心过程方法->

    synchronized void doConnect(InetAddress address, int port, int timeout) {

        synchronized (fdLock) {

            if (!closePending && (socket == null || !socket.isBound())) {

                NetHooks.beforeTcpConnect(fd, address, port);

            }

        }

        try {

            acquireFD();

            //与Socket服务器InetSocketAddress[address,port]建立连接

            socketConnect(address, port, timeout);

           ....

}

 3.5)socketConnect(address, port, timeout), 跟踪核心过程方法-> 

    socketConnect最终分支为两个实现:DualStackPlainSocketImpl实现类的static native int connect0(int fd, InetAddress remote, int remotePort) 方法 或TwoStacksPlainSocketImpl实现类的native void socketConnect(InetAddress address, int port, int timeout) 

3.6)在建立连接完后,客户端可向服务器端发送信息(OutputStream os = socket.getOutputStream();字节输出流), 跟踪核心过程方法->

    public OutputStream getOutputStream() throws IOException {

        ......

        OutputStream os = null;

        try {

            os = AccessController.doPrivileged(

                new PrivilegedExceptionAction<OutputStream>() {

                    public OutputStream run() throws IOException {

                        return impl.getOutputStream();

                    }

                });

            ....

          return os;}

 

impl.getOutputStream(), 跟踪核心过程方法->

   //Gets an OutputStream for this socket.

    protected synchronized OutputStream getOutputStream() {

        synchronized (fdLock) {

            if (isClosedOrPending())   throw new IOException("Socket Closed");

            if (shut_wr) throw new IOException("Socket output is shutdown");

            if (socketOutputStream == null)

            //Creates a new SocketOutputStream. Can only be called by a Socket. This method needs to hang on to the owner Socket

                socketOutputStream = new SocketOutputStream(this);

        }

        return socketOutputStream;

    } 

3.7)在建立连接完后,客户端接收向服务器端发送的信息(InputStream is=socket

.getInputStream()获取输入流), 设计思想同getOutputStream()完全一致。

 

3.8)Closes this socket

    public void close() throws IOException {

        synchronized(closeLock) {

            if (isClosed())

                return;

            if (created)

                impl.close();

            closed = true;

        }

    }


Socket服务端ServerSocket类分析

 
#构造ServerSocket(1个默认构造函数,2个带参构造函数)

public ServerSocket()

public ServerSocket(int port) //创建Socket服务端

3.1)创建Socket服务端, 跟踪核心过程方法->

public ServerSocket(int port, int backlog, InetAddress bindAddr) {

        setImpl();同客户端设置SocketImpl一致

        ...

        try {

            //初始化InetSocketAddress,并bind 

            bind(new InetSocketAddress(bindAddr, port), backlog);

        } ...}

 

Bind方法, 跟踪核心过程方法->

Public void bind(SocketAddress endpoint, int backlog){

        ......

        InetSocketAddress epoint = (InetSocketAddress) endpoint;

        try {

            ......

            //Socket绑定对端点并监听

            getImpl().bind(epoint.getAddress(), epoint.getPort());

            getImpl().listen(backlog);

            ......

    }

  深入bind方法,最终至static native void bind0(int fd, InetAddress localAddress, int localport,boolean exclBind) 或native void socketBind(InetAddress address, int port, boolean exclBind)

  深入listen方法,最终至static native void listen0(int fd, int backlog) 或  native void socketListen(int count)

 

3.2)监听[public Socket accept()],等待客户端的连接, 跟踪核心过程方法->

  public Socket accept() throws IOException {

        .....

        //创建可被接收,监听的Socket(客户端)对象

        Socket s = new Socket((SocketImpl) null);

        implAccept(s);//监听Socket

        return s;

 }

3.3)数据通信:调用Socket类的getInputStream()接收客户端数据,且调用getOutputStream()向客户端回复信息

 

3.4)Closes this socket

    public void close() throws IOException {

        synchronized(closeLock) {

            if (isClosed())

                return;

            if (created)

                impl.close();

            closed = true;

        }

}

 UDP部分-暂不研究