java.nio.channels.ServerSocketChannel

1.ServerSocketChannel的父子继承关系

在这里插入图片描述

2. ServerSocketChannel注释

1). 调用#open()方法创建server-socket channel
2). 在还未绑定的server-socket channel上尝试去调用#accept()方法会抛出一个NotYetBoundException异常
3). server-socket channel可以通过调用这个类定义的#bind(java.net.SocketAddress local, int backlog)方法来进行绑定
4). Server-socket channels在多个并发线程使用时是安全的

/**
 * A selectable channel for stream-oriented listening sockets.
 * ServerSocketChannel是给面向流的监听socket的一个可选通道
 *
 * <p> A server-socket channel is created by invoking one of the {@code open}
 * methods of this class. The no-arg {@link #open() open} method opens a server-socket
 * channel for an <i>Internet protocol</i> socket. The {@link #open(ProtocolFamily)}
 * method is used to open a server-socket channel for a socket of a specified
 * protocol family. It is not possible to create a channel for an arbitrary,
 * pre-existing socket. A newly-created server-socket channel is open but not yet
 * bound. An attempt to invoke the {@link #accept() accept} method of an
 * unbound server-socket channel will cause a {@link NotYetBoundException}
 * to be thrown. A server-socket channel can be bound by invoking one of the
 * {@link #bind(java.net.SocketAddress, int) bind} methods defined by this class.
 * 通过调用这个类的#open()方法创建server-socket channel
 * #open()无参方法给网络协议socket创建server-socket channel
 * #open(ProtocolFamily)方法被用来去给一个指定协议族的socket去创建一个server-socket channel
 * 不能去给一个任意预先存在的socket创建channel
 * 一个新创建的server-socket channel是open状态,但是还没有进行绑定
 * 在还未绑定的server-socket channel上尝试去调用#accept()方法会抛出一个NotYetBoundException异常
 * server-socket channel可以通过调用这个类定义的#bind(java.net.SocketAddress local, int backlog)方法来进行绑定
 *
 * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
 * setOption} method. Server-socket channels for <i>Internet protocol</i> sockets
 * support the following options:
 * <blockquote>
 * <table class="striped">
 * <caption style="display:none">Socket options</caption>
 * <thead>
 *   <tr>
 *     <th scope="col">Option Name</th>
 *     <th scope="col">Description</th>
 *   </tr>
 * </thead>
 * <tbody>
 *   <tr>
 *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </th>
 *     <td> The size of the socket receive buffer </td>
 *   </tr>
 *   <tr>
 *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </th>
 *     <td> Re-use address </td>
 *   </tr>
 * </tbody>
 * </table>
 * </blockquote>
 *
 * <p> Server-socket channels for <i>Unix domain</i> sockets support:
 * <blockquote>
 * <table class="striped">
 * <caption style="display:none">Socket options</caption>
 * <thead>
 *   <tr>
 *     <th scope="col">Option Name</th>
 *     <th scope="col">Description</th>
 *   </tr>
 * </thead>
 * <tbody>
 *   <tr>
 *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </th>
 *     <td> The size of the socket receive buffer </td>
 *   </tr>
 * </tbody>
 * </table>
 * </blockquote>
 *
 * <p> Additional (implementation specific) options may also be supported.
 *
 * <p> Server-socket channels are safe for use by multiple concurrent threads.
 * Server-socket channels在多个并发线程使用时是安全的
 * </p>
 *
 * @author Mark Reinhold
 * @author JSR-51 Expert Group
 * @since 1.4
 */

public abstract class ServerSocketChannel
    extends AbstractSelectableChannel
    implements NetworkChannel
{
}

3. ServerSocketChannel提供的方法

在这里插入图片描述

1). bind(SocketAddress, int)

    /**
     * Binds the channel's socket to a local address and configures the socket to
     * listen for connections.
     *
     * <p> This method is used to establish an association between the socket and
     * a local address. For <i>Internet protocol</i> sockets, once an association
     * is established then the socket remains bound until the channel is closed.
     *
     * <p> The {@code backlog} parameter is the maximum number of pending
     * connections on the socket. Its exact semantics are implementation specific.
     * In particular, an implementation may impose a maximum length or may choose
     * to ignore the parameter altogether. If the {@code backlog} parameter has
     * the value {@code 0}, or a negative value, then an implementation specific
     * default is used.
     *
     * @apiNote
     * Binding a server socket channel for a <i>Unix Domain</i> socket, creates a
     * file corresponding to the file path in the {@link UnixDomainSocketAddress}.
     * This file persists after the channel is closed, and must be removed before
     * another socket can bind to the same name. Binding to a {@code null} address
     * causes the socket to be <i>automatically</i> bound to some unique file
     * in a system temporary location. The associated socket file also persists
     * after the channel is closed. Its name can be obtained from the channel's
     * local socket address.
     *
     * @implNote
     * Each platform enforces an implementation specific, maximum length for the
     * name of a <i>Unix Domain</i> socket. This limitation is enforced when a
     * channel is bound. The maximum length is typically close to and generally
     * not less than 100 bytes. This limitation also applies to <i>automatically</i>
     * bound server socket channels. See the <i>Unix domain</i>
     * <a href="../../net/doc-files/net-properties.html#Unixdomain">networking
     * properties</a> that can be used to select the temporary directory where
     * these sockets are created.
     *
     * @param   local
     *          The address to bind the socket, or {@code null} to bind to
     *          an automatically assigned socket address
     * @param   backlog
     *          The maximum number of pending connections
     *
     * @return  This channel
     *
     * @since 1.7
     */
    public abstract ServerSocketChannel bind(SocketAddress local, int backlog)
        throws IOException;

2). open()

    /**
     * Opens a server-socket channel for an <i>Internet protocol</i> socket.
     *
     * <p> The new channel is created by invoking the {@link
     * java.nio.channels.spi.SelectorProvider#openServerSocketChannel
     * openServerSocketChannel} method of the system-wide default {@link
     * java.nio.channels.spi.SelectorProvider} object.
     *
     * <p> The new channel's socket is initially unbound; it must be bound to a
     * specific address via one of its socket's {@link
     * java.net.ServerSocket#bind(SocketAddress) bind} methods before
     * connections can be accepted.  </p>
     *
     * @return  A new socket channel
     */
    public static ServerSocketChannel open() throws IOException {
        return SelectorProvider.provider().openServerSocketChannel();
    }

3). accept()

(1). 如果这个channel处于non-blocking非阻塞模式,并且如果没有挂起的连接,那么这个方法就会立即返回null
(2). 如果这个channel处于blocking阻塞模式,他就会一直阻塞,直到可以获得一个新的连接,或者发生了I/O错误。
(3). 无论这个channel的阻塞模式是什么样的,这个方法返回的SocketChannel都会是阻塞模式
(4). 根据UNIX socket或者INET socket进行不同的安全检查

    /**
     * Accepts a connection made to this channel's socket.
     * 给这个channel的socket接收一个连接
     * 
     * <p> If this channel is in non-blocking mode then this method will
     * immediately return {@code null} if there are no pending connections.
     * Otherwise it will block indefinitely until a new connection is available
     * or an I/O error occurs.
     * 如果这个channel处于non-blocking非阻塞模式,并且如果没有挂起的连接,那么这个方法就会立即返回null
     * 否则他就会一直阻塞,直到可以获得一个新的连接,或者发生了I/O错误。
     *
     * <p> The socket channel returned by this method, if any, will be in
     * blocking mode regardless of the blocking mode of this channel.
     * 无论这个channel的阻塞模式是什么样的,这个方法返回的socket channel都会是阻塞模式
     *
     * <p> If bound to an <i>Internet protocol</i> socket address, this method
     * performs exactly the same security checks as the {@link
     * java.net.ServerSocket#accept accept} method of the {@link java.net.ServerSocket}
     * class.  That is, if a security manager has been installed then for each
     * new connection this method verifies that the address and port number
     * of the connection's remote endpoint are permitted by the security
     * manager's {@link java.lang.SecurityManager#checkAccept checkAccept}
     * method. If bound to a <i>Unix Domain</i> socket address, this method checks
     * {@link NetPermission}{@code ("accessUnixDomainSocket")}.
     * 如果绑定到一个网络协议socket地址,这个方法会和java.net.ServerSocket类的accept方法一样,也会进行合适的安全检查
     * 如果一个安全管理已经安装了,那么对于每一个新的连接,此方法将验证安全管理器的checkAccept方法是否允许连接的远程端点的地址和端口号。
     * 如果绑定到一个Unix Domain socket地址,这个方法会通过accessUnixDomainSocket检查网络许可。
     *
     * @return  The socket channel for the new connection,
     *          or {@code null} if this channel is in non-blocking mode
     *          and no connection is available to be accepted
     */
    public abstract SocketChannel accept() throws IOException;

ServerSocketChannelImpl为accpet()方法提供了实现

    // Lock held by thread currently blocked on this channel
    private final ReentrantLock acceptLock = new ReentrantLock();
    
    @Override
    public SocketChannel accept() throws IOException {
        int n = 0;
        // 文件描述符
        FileDescriptor newfd = new FileDescriptor();
        // socket地址
        SocketAddress[] saa = new SocketAddress[1];

        acceptLock.lock();
        try {
        	// 阻塞模式 blocking = true
            boolean blocking = isBlocking();
            try {
                begin(blocking);
                n = implAccept(this.fd, newfd, saa);
                if (blocking) {
                    while (IOStatus.okayToRetry(n) && isOpen()) {
                        park(Net.POLLIN);
                        n = implAccept(this.fd, newfd, saa);
                    }
                }
            } finally {
                end(blocking, n > 0);
                assert IOStatus.check(n);
            }
        } finally {
            acceptLock.unlock();
        }

        if (n > 0) {
            return finishAccept(newfd, saa[0]);
        } else {
            return null;
        }
    }

    /**
     * Marks the beginning of an I/O operation that might block.
     *
     * @throws ClosedChannelException if the channel is closed
     * @throws NotYetBoundException if the channel's socket has not been bound yet
     */
    private void begin(boolean blocking) throws ClosedChannelException {
        if (blocking)
            begin();  // set blocker to close channel if interrupted
        synchronized (stateLock) {
            ensureOpen();
            if (localAddress == null)
                throw new NotYetBoundException();
            if (blocking)
                thread = NativeThread.current();
        }
    }

    private int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] saa)
        throws IOException
    {
        if (isUnixSocket()) {
            UnixDomainSockets.checkPermission();
            String[] pa = new String[1];
            int n = UnixDomainSockets.accept(fd, newfd, pa);
            if (n > 0)
                saa[0] = UnixDomainSocketAddress.of(pa[0]);
            return n;
        } else {
            InetSocketAddress[] issa = new InetSocketAddress[1];
            int n = Net.accept(fd, newfd, issa);
            if (n > 0)
                saa[0] = issa[0];
            return n;
        }
    }

    private SocketChannel finishAccept(FileDescriptor newfd, SocketAddress sa)
        throws IOException
    {
        try {
            // newly accepted socket is initially in blocking mode
            IOUtil.configureBlocking(newfd, true);

            // check permitted to accept connections from the remote address
            if (isNetSocket()) {
                @SuppressWarnings("removal")
                SecurityManager sm = System.getSecurityManager();
                if (sm != null) {
                    InetSocketAddress isa = (InetSocketAddress) sa;
                    sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
                }
            }
            return new SocketChannelImpl(provider(), family, newfd, sa);
        } catch (Exception e) {
            nd.close(newfd);
            throw e;
        }
    }

java.nio.channels.spi.AbstractSelectableChannel#isBlocking()方法默认实现

    // Blocking mode, protected by regLock
    boolean blocking = true;
    
    public final boolean isBlocking() {
        synchronized (regLock) {
            return blocking;
        }
    }

java.nio.channels.spi.AbstractSelectableChannel#begin()方法默认实现如下:

    /**
     * Marks the beginning of an I/O operation that might block indefinitely.
     *
     * <p> This method should be invoked in tandem with the {@link #end end}
     * method, using a {@code try}&nbsp;...&nbsp;{@code finally} block as
     * shown <a href="#be">above</a>, in order to implement asynchronous
     * closing and interruption for this channel.  </p>
     */
    protected final void begin() {
        if (interruptor == null) {
            interruptor = new Interruptible() {
                    public void interrupt(Thread target) {
                        synchronized (closeLock) {
                            if (closed)
                                return;
                            closed = true;
                            interrupted = target;
                            try {
                                AbstractInterruptibleChannel.this.implCloseChannel();
                            } catch (IOException x) { }
                        }
                    }};
        }
        blockedOn(interruptor);
        Thread me = Thread.currentThread();
        if (me.isInterrupted())
            interruptor.interrupt(me);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值