Java 日看一类(61)AbstractPlainSocketImpl类

66 篇文章 3 订阅
9 篇文章 0 订阅

该类继承自SocketImpl类

该类引入了如下包:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileDescriptor;

import sun.net.ConnectionResetException;
import sun.net.NetHooks;
import sun.net.ResourceManager;



该类的类头注释如下:

/**
 * Default Socket Implementation. This implementation does
 * not implement any security checks.
 * Note this class should <b>NOT</b> be public.
 *
 * @author  Steven B. Byrne
 */

大意如下:

默认的套接字实现方式

该实现方式不执行一些安全检查

该类非public类



该类含有如下的成员变量:

超时时间

int timeout; 

IP服务类型

private int trafficClass;

中止读取信号

private boolean shut_rd = false;

中止写入信号

private boolean shut_wr = false;

套接字输入流

private SocketInputStream socketInputStream = null;

套接字输出流

private SocketOutputStream socketOutputStream = null;

使用文件描述符的线程数

protected int fdUseCount = 0;

文件描述符控制锁

protected final Object fdLock = new Object();

文件描述符的关闭状态

protected boolean closePending = false;

连接状态指示

private int CONNECTION_NOT_RESET = 0;
private int CONNECTION_RESET_PENDING = 1;
private int CONNECTION_RESET = 2;

针对上述种类的状态记录

private int resetState;

重置锁

private final Object resetLock = new Object();

判定是TCP还是UDP(true是TCP,false是UDP;不过不是很清楚为啥要叫字段stream……)

protected boolean stream;

常量声明

public final static int SHUT_RD = 0;
public final static int SHUT_WR = 1;



该类含有如下的成员方法:

构造函数(同步的构造函数,需要运输层传送方法)

protected synchronized void create(boolean stream) throws IOException {
    this.stream = stream;
    if (!stream) {//为UDP
        ResourceManager.beforeUdpCreate();
        // only create the fd after we know we will be able to create the socket
        fd = new FileDescriptor();
        try {
            socketCreate(false);//创建UDP的Socket
        } catch (IOException ioe) {
            ResourceManager.afterUdpClose();
            fd = null;
            throw ioe;
        }
    } else {//创建TCP
        fd = new FileDescriptor();
        socketCreate(true);
    }
    if (socket != null)
        socket.setCreated();//父类包含的Socket变量
    if (serverSocket != null)
        serverSocket.setCreated();//父类包含的ServerSocket
}

创建连接(目标主机名和目的端口

protected void connect(String host, int port)
    throws UnknownHostException, IOException
{
    boolean connected = false;
    try {
        InetAddress address = InetAddress.getByName(host);//DNS获得主机地址
        this.port = port;
        this.address = address;

        connectToAddress(address, port, timeout);//创建连接
        connected = true;
    } finally {
        if (!connected) {//连接失败
            try {
                close();//关闭Socket
            } catch (IOException ioe) {
                /* Do nothing. If connect threw an exception then
                   it will be passed up the call stack */
            }
        }
    }
}

创建连接(主机地址和端口

protected void connect(InetAddress address, int port) throws IOException {
    this.port = port;
    this.address = address;

    try {
        connectToAddress(address, port, timeout);
        return;
    } catch (IOException e) {
        // everything failed
        close();
        throw e;
    }
}

创建连接(一个完成SockAddress接口的(主机地址),和连接时限)

protected void connect(SocketAddress address, int timeout)
        throws IOException {
    boolean connected = false;
    try {
        if (address == null || !(address instanceof InetSocketAddress))//不是实际地址就炸
            throw new IllegalArgumentException("unsupported address type");
        InetSocketAddress addr = (InetSocketAddress) address;
        if (addr.isUnresolved())
            throw new UnknownHostException(addr.getHostName());
        this.port = addr.getPort();
        this.address = addr.getAddress();

        connectToAddress(this.address, port, timeout);
        connected = true;
    } finally {
        if (!connected) {
            try {
                close();
            } catch (IOException ioe) {
                /* Do nothing. If connect threw an exception then
                   it will be passed up the call stack */
            }
        }
    }
}

创建连接(上面一个的进化版,多了时限

private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
    if (address.isAnyLocalAddress()) {//判定是不是本地地址
        doConnect(InetAddress.getLocalHost(), port, timeout);
    } else {
        doConnect(address, port, timeout);
    }
}

网络连接权限(根据具体的操作号,后面对应的实体种类不同),该方法只是整合参数,具体设置在SocketSetOption里

public void setOption(int opt, Object val) throws SocketException {
    if (isClosedOrPending()) {//判定当前套接字状态
        throw new SocketException("Socket Closed");
    }
    boolean on = true;
    switch (opt) {//根据操作权限码选择
        /* check type safety b4 going native.  These should never
         * fail, since only java.Socket* has access to
         * PlainSocketImpl.setOption().
         */
    case SO_LINGER:
        if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
            throw new SocketException("Bad parameter for option");
        if (val instanceof Boolean) {
            /* true only if disabling - enabling should be Integer */
            on = false;
        }
        break;
    case SO_TIMEOUT://设置超时时限
        if (val == null || (!(val instanceof Integer)))
            throw new SocketException("Bad parameter for SO_TIMEOUT");
        int tmp = ((Integer) val).intValue();
        if (tmp < 0)
            throw new IllegalArgumentException("timeout < 0");
        timeout = tmp;
        break;
    case IP_TOS://设置IP头控制字段(type of service
         if (val == null || !(val instanceof Integer)) {
             throw new SocketException("bad argument for IP_TOS");
         }
         trafficClass = ((Integer)val).intValue();//设置控制字段
         break;
    case SO_BINDADDR://绑定地址
        throw new SocketException("Cannot re-bind socket");
    case TCP_NODELAY://TCP 无延迟发包
        if (val == null || !(val instanceof Boolean))
            throw new SocketException("bad parameter for TCP_NODELAY");
        on = ((Boolean)val).booleanValue();
        break;
    case SO_SNDBUF:
    case SO_RCVBUF://设置发送和接收缓冲大小
        if (val == null || !(val instanceof Integer) ||
            !(((Integer)val).intValue() > 0)) {
            throw new SocketException("bad parameter for SO_SNDBUF " +
                                      "or SO_RCVBUF");
        }
        break;
    case SO_KEEPALIVE://链接保持
        if (val == null || !(val instanceof Boolean))
            throw new SocketException("bad parameter for SO_KEEPALIVE");
        on = ((Boolean)val).booleanValue();
        break;
    case SO_OOBINLINE:
        if (val == null || !(val instanceof Boolean))
            throw new SocketException("bad parameter for SO_OOBINLINE");
        on = ((Boolean)val).booleanValue();
        break;
    case SO_REUSEADDR://重定位地址
        if (val == null || !(val instanceof Boolean))
            throw new SocketException("bad parameter for SO_REUSEADDR");
        on = ((Boolean)val).booleanValue();
        break;
    default:
        throw new SocketException("unrecognized TCP option: " + opt);
    }
    socketSetOption(opt, on, val);
}

获得具体操作设置字段的值(逻辑基本和上一个方法一样

public Object getOption(int opt) throws SocketException {
    if (isClosedOrPending()) {
        throw new SocketException("Socket Closed");
    }
    if (opt == SO_TIMEOUT) {
        return new Integer(timeout);
    }
    int ret = 0;
    /*
     * The native socketGetOption() knows about 3 options.
     * The 32 bit value it returns will be interpreted according
     * to what we're asking.  A return of -1 means it understands
     * the option but its turned off.  It will raise a SocketException
     * if "opt" isn't one it understands.
     */

    switch (opt) {
    case TCP_NODELAY:
        ret = socketGetOption(opt, null);
        return Boolean.valueOf(ret != -1);
    case SO_OOBINLINE:
        ret = socketGetOption(opt, null);
        return Boolean.valueOf(ret != -1);
    case SO_LINGER:
        ret = socketGetOption(opt, null);
        return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret));
    case SO_REUSEADDR:
        ret = socketGetOption(opt, null);
        return Boolean.valueOf(ret != -1);
    case SO_BINDADDR:
        InetAddressContainer in = new InetAddressContainer();
        ret = socketGetOption(opt, in);
        return in.addr;
    case SO_SNDBUF:
    case SO_RCVBUF:
        ret = socketGetOption(opt, null);
        return new Integer(ret);
    case IP_TOS:
        try {
            ret = socketGetOption(opt, null);
            if (ret == -1) { // ipv6 tos
                return trafficClass;
            } else {
                return ret;
            }
        } catch (SocketException se) {
            // TODO - should make better effort to read TOS or TCLASS
            return trafficClass; // ipv6 tos
        }
    case SO_KEEPALIVE:
        ret = socketGetOption(opt, null);
        return Boolean.valueOf(ret != -1);
    // should never get here
    default:
        return null;
    }
}

同步进行TCP链接

synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
    synchronized (fdLock) {
        if (!closePending && (socket == null || !socket.isBound())) {
            NetHooks.beforeTcpConnect(fd, address, port);//建立TCP
        }
    }
    try {
        acquireFD();//获得当前套接字的描述符
        try {
            socketConnect(address, port, timeout);
            /* socket may have been closed during poll/select */
            synchronized (fdLock) {
                if (closePending) {
                    throw new SocketException ("Socket closed");
                }
            }
            // If we have a ref. to the Socket, then sets the flags
            // created, bound & connected to true.
            // This is normally done in Socket.connect() but some
            // subclasses of Socket may call impl.connect() directly!
            if (socket != null) {
                socket.setBound();
                socket.setConnected();
            }
        } finally {
            releaseFD();//归还文件描述符的使用权
        }
    } catch (IOException e) {
        close();
        throw e;
    }
}

对某个端口监听(参数是时间)

protected synchronized void listen(int count) throws IOException {
    socketListen(count);
}

接收某个连接请求(来自Scoket实例

protected void accept(SocketImpl s) throws IOException {
    acquireFD();
    try {
        socketAccept(s);
    } finally {
        releaseFD();
    }
}

获得Socket的数据输入流

protected synchronized InputStream getInputStream() throws IOException {
    synchronized (fdLock) {
        if (isClosedOrPending())
            throw new IOException("Socket Closed");
        if (shut_rd)
            throw new IOException("Socket input is shutdown");
        if (socketInputStream == null)
            socketInputStream = new SocketInputStream(this);
    }
    return socketInputStream;
}

设置数据输入流为特定输入流

void setInputStream(SocketInputStream in) {
    socketInputStream = in;
}

获得套接字输出流(就是发送给链接方的数据

protected synchronized OutputStream getOutputStream() throws IOException {
    synchronized (fdLock) {
        if (isClosedOrPending())
            throw new IOException("Socket Closed");
        if (shut_wr)
            throw new IOException("Socket output is shutdown");
        if (socketOutputStream == null)
            socketOutputStream = new SocketOutputStream(this);
    }
    return socketOutputStream;
}

设置当前的所操作的Socket(实质Socket和文件描述符绑定

void setFileDescriptor(FileDescriptor fd) {
    this.fd = fd;
}

设置目的主机地址

void setAddress(InetAddress address) {
    this.address = address;
}

设置目的端口

void setPort(int port) {
    this.port = port;
}

设置本地监听端口

void setLocalPort(int localport) {
    this.localport = localport;
}

返回当前Socket链接的有效性

protected synchronized int available() throws IOException {
    if (isClosedOrPending()) {
        throw new IOException("Stream closed.");
    }

    /*
     * If connection has been reset or shut down for input, then return 0
     * to indicate there are no buffered bytes.
     */
    if (isConnectionReset() || shut_rd) {
        return 0;
    }

    /*
     * If no bytes available and we were previously notified
     * of a connection reset then we move to the reset state.
     *
     * If are notified of a connection reset then check
     * again if there are bytes buffered on the socket.
     */
    int n = 0;
    try {
        n = socketAvailable();//当前无效
        if (n == 0 && isConnectionResetPending()) {//重新设置链接
            setConnectionReset();
        }
    } catch (ConnectionResetException exc1) {
        setConnectionResetPending();//设置成预备重设状态
        try {
            n = socketAvailable();//再次尝试获得有效性
            if (n == 0) {//如果仍然无效就再次重设
                setConnectionReset();
            }
        } catch (ConnectionResetException exc2) {
        }
    }
    return n;
}

关闭链接

protected void close() throws IOException {
    synchronized(fdLock) {
        if (fd != null) {
            if (!stream) {
                ResourceManager.afterUdpClose();
            }
            if (fdUseCount == 0) {
                if (closePending) {
                    return;
                }
                closePending = true;
                /*
                 * We close the FileDescriptor in two-steps - first the
                 * "pre-close" which closes the socket but doesn't
                 * release the underlying file descriptor. This operation
                 * may be lengthy due to untransmitted data and a long
                 * linger interval. Once the pre-close is done we do the
                 * actual socket to release the fd.
                 */
                try {
                    socketPreClose();
                } finally {
                    socketClose();
                }
                fd = null;
                return;
            } else {
                /*
                 * If a thread has acquired the fd and a close
                 * isn't pending then use a deferred close.
                 * Also decrement fdUseCount to signal the last
                 * thread that releases the fd to close it.
                 */
                if (!closePending) {
                    closePending = true;
                    fdUseCount--;
                    socketPreClose();
                }
            }
        }
    }
}

重新设置链接

void reset() throws IOException {
    if (fd != null) {
        socketClose();
    }
    fd = null;
    super.reset();
}

中止从套接字中输入数据

protected void shutdownInput() throws IOException {
  if (fd != null) {
      socketShutdown(SHUT_RD);
      if (socketInputStream != null) {
          socketInputStream.setEOF(true);
      }
      shut_rd = true;
  }
}

中止向套接字中输出数据

protected void shutdownOutput() throws IOException {
  if (fd != null) {
      socketShutdown(SHUT_WR);
      shut_wr = true;
  }
}

支持立即提交功能

protected boolean supportsUrgentData () {
    return true;
}

发送紧急数据

protected void sendUrgentData (int data) throws IOException {
    if (fd == null) {
        throw new IOException("Socket Closed");
    }
    socketSendUrgentData (data);
}

最终操作(一般是用户用完忘了关

protected void finalize() throws IOException {
    close();

}

请求文件描述符(对该套接字使用请求

FileDescriptor acquireFD() {
    synchronized (fdLock) {
        fdUseCount++;
        return fd;
    }
}

释放文件描述符(对该套接字释放

void releaseFD() {
    synchronized (fdLock) {
        fdUseCount--;
        if (fdUseCount == -1) {
            if (fd != null) {
                try {
                    socketClose();
                } catch (IOException e) {
                } finally {
                    fd = null;
                }
            }
        }
    }
}

返回状态位(是否重置链接

public boolean isConnectionReset() {
    synchronized (resetLock) {
        return (resetState == CONNECTION_RESET);
    }
}

返回状态位(是否期待重设链接

public boolean isConnectionResetPending() {
    synchronized (resetLock) {
        return (resetState == CONNECTION_RESET_PENDING);
    }
}

设置状态位(链接重置

public void setConnectionReset() {
    synchronized (resetLock) {
        resetState = CONNECTION_RESET;
    }
}

设置状态位(链接需要重置

public void setConnectionResetPending() {
    synchronized (resetLock) {
        if (resetState == CONNECTION_NOT_RESET) {
            resetState = CONNECTION_RESET_PENDING;
        }
    }

}

是否已经关闭或者期待关闭

public boolean isClosedOrPending() {
    /*
     * Lock on fdLock to ensure that we wait if a
     * close is in progress.
     */
    synchronized (fdLock) {
        if (closePending || (fd == null)) {
            return true;
        } else {
            return false;
        }
    }
}

返回超时时长

public int getTimeout() {
    return timeout;
}

预关闭套接字(不释放文件描述符和资源

private void socketPreClose() throws IOException {
    socketClose0(true);
}

关闭套接字(释放资源和描述符

protected void socketClose() throws IOException {
    socketClose0(false);
}


接下来是一些需要完成的方法,方法用途可以通过名称判断:

abstract void socketCreate(boolean isServer) throws IOException;
abstract void socketConnect(InetAddress address, int port, int timeout)
    throws IOException;
abstract void socketBind(InetAddress address, int port)
    throws IOException;
abstract void socketListen(int count)
    throws IOException;
abstract void socketAccept(SocketImpl s)
    throws IOException;
abstract int socketAvailable()
    throws IOException;
abstract void socketClose0(boolean useDeferredClose)
    throws IOException;
abstract void socketShutdown(int howto)
    throws IOException;
abstract void socketSetOption(int cmd, boolean on, Object value)
    throws SocketException;
abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
abstract void socketSendUrgentData(int data)
    throws IOException;




该类含有如下的静态代码块(初始化网络库的运行环境

static {
    java.security.AccessController.doPrivileged(//无视安全检查
        new java.security.PrivilegedAction<Void>() {
            public Void run() {
                System.loadLibrary("net");
                return null;
            }
        });
}



该类属于Socket的基本模版,主要为套接字定下了一个大的框架,计算机网络知识中的一些操作在这里也得到体现,如紧急提交标志位等,该类的阅读需要一定的计算机网络基础,否则可能难以准确理解实际意义。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值