Mina socket listener (NioSocketAcceptor)

Mina IoService interface definition and abstract implementation: http://donald-draper.iteye.com/blog/2378271
Mina Io listener interface definition and abstract implementation: http://donald-draper.iteye.com/blog/2378315
Mina abstraction Polling listener: http://donald-draper.iteye.com/blog/2378649
Introduction:
   The last article saw the abstract polling listener, let's review it first:
The main variables of AbstractPollingIoAcceptor are the Io processor processor, the address binding request queue registerQueue, the address unbinding request queue cancelQueue, the socket address bound to the listener, the boundHandles-Map mapping relationship with ServerSocketChannel, and the listener worker thread Acceptor refers to acceptorRef. Constructing AbstractPollingIoAcceptor is mainly to initialize session configuration, Io processor type, if IO asynchronous event executor is empty, it defaults to CachedThreadPool, and then initializes the selector. The address binding process is to create the result of the binding operation, register the binding request to the registered address binding request queue, create the listener Acceptor instance and execute it. The main functions of the Acceptor are: address binding, listening for connection requests, and unbinding addresses. The actual working logic is: if the listener AbstractPollingIoAcceptor has been initialized, first open a ServerSocketChannel according to the binding request in the address binding queue, and register to receive the event OP_ACCEPT to Selector, and add the binding address and ServerSocketChannel mapping management to the address binding mapping set; perform the selection operation, if the actual binding address is empty, then empty the acceptorRef; if the receive connection event occurs, process the connection request, traverse the receive Event-ready ServerSocketChannel, ServerSocketChannel creates a session associated with the processor, initializes the session, adds the session to the session associated io processor; checks whether there is an address unbinding request, if there is an unbinding request CancellationRequest, from the bound socket address and ServerSocketChannel mapping map , remove the bound socket address, close the ServerSocketChannel; finally check whether the listener is closing, if the acceptor is closing, close the associated processor. The relationship between Acceptor and AbstractPollingIoAcceptor, with AbstractPollingIoProcessor and Proce The relationship of ssor is very similar. In the process of address unbinding, first create an AcceptorOperationFuture according to the unbinding address, add it to the unbinding queue, start the Acceptor thread, and complete the actual unbinding work.
All the work of AbstractPollingIoAcceptor (address binding, receiving connections, creating sessions, adding sessions to IO handlers, unbinding addresses, and releasing listener resources) is done in the Acceptor thread.
Today, let's take a look at the implementation of the abstract polling listener NioSocketAcceptor
/**
 * {@link IoAcceptor} for socket transport (TCP/IP).  This class
 * handles incoming TCP/IP based socket connections.
 *socket listener, receiving socket connections.
 * @author [url=http://mina.apache.org]Apache MINA Project[/url]
 */
public final class NioSocketAcceptor extends AbstractPollingIoAcceptor<NioSession, ServerSocketChannel>
implements SocketAcceptor {
    private volatile Selector selector;//Selector
    private volatile SelectorProvider selectorProvider = null;//Selector provider
}

Looking at socket listening from above, there are two internal variables that provide selector provider for selector and selector.
Let's look at the structure again:
/**
  * Constructor for {@link NioSocketAcceptor} using default parameters
  (multiple thread model).
  Default parameters, multithreaded model
  */
 public NioSocketAcceptor() {
     super(new DefaultSocketSessionConfig(), NioProcessor.class);
     ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
 }

 /**
  * Constructor for {@link NioSocketAcceptor} using default parameters, and
  * given number of {@link NioProcessor} for multithreading I/O operations.
  * Construct with default parameters, create processorCount NioProcessor processor threads, and process IO operations with multiple threads
  * @param processorCount the number of processor to create and place in a
  * {@link SimpleIoProcessorPool}
  */
 public NioSocketAcceptor(int processorCount) {
     super(new DefaultSocketSessionConfig(), NioProcessor.class, processorCount);
     ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
 }

 /**
  *  Constructor for {@link NioSocketAcceptor} with default configuration but a
  *  specific {@link IoProcessor}, useful for sharing the same processor over multiple
  *  {@link IoService} of the same type.
  Multiple services share the same processor,
  * @param processor the processor to use for managing I/O events
  */
 public NioSocketAcceptor(IoProcessor<NioSession> processor) {
     super(new DefaultSocketSessionConfig(), processor);
     ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
 }

 /**
  *  Constructor for {@link NioSocketAcceptor} with a given {@link Executor} for handling
  *  connection events and a given {@link IoProcessor} for handling I/O events, useful for
  *  sharing the same processor and executor over multiple {@link IoService} of the same type.
  Multiple services share the same processor, and use a given executor to handle connection events and a given processor to handle IO events.
  * @param executor the executor for connection
  * @param processor the processor for I/O operations
  */
 public NioSocketAcceptor(Executor executor, IoProcessor<NioSession> processor) {
     super(new DefaultSocketSessionConfig(), executor, processor);
     ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
 }

 /**
  * Constructor for {@link NioSocketAcceptor} using default parameters, and
  * given number of {@link NioProcessor} for multithreading I/O operations, and
  * a custom SelectorProvider for NIO
  *Multiprocessor handles multithreaded IO operations
  * @param processorCount the number of processor to create and place in a
  * @param selectorProvider teh SelectorProvider to use
  * {@link SimpleIoProcessorPool}
  */
 public NioSocketAcceptor(int processorCount, SelectorProvider selectorProvider) {
     super(new DefaultSocketSessionConfig(), NioProcessor.class, processorCount, selectorProvider);
     ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
     this.selectorProvider = selectorProvider;
 }

The above construction methods are basically the same as AbstractPollingIoAcceptor.
Let's look at other operations:
   /**
     * {@inheritDoc}
     */
    @Override
    protected void init() throws Exception {
        selector = Selector.open();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected void init(SelectorProvider selectorProvider) throws Exception {
        this.selectorProvider = selectorProvider;

        if (selectorProvider == null) {
            selector = Selector.open();
        } else {
            selector = selectorProvider.openSelector();
        }
    }

From the above two methods, the init method mainly works to open a selector selector.
  
/**
     * {@inheritDoc}
     */
    @Override
    protected void destroy() throws Exception {
        if (selector != null) {
            selector.close();
        }
    }
    /**
     * {@inheritDoc}
     */
    public TransportMetadata getTransportMetadata() {
        return NioSocketSession.METADATA;
    }
   /**
     * {@inheritDoc}
     */
    @Override
    public InetSocketAddress getLocalAddress() {
        return (InetSocketAddress) super.getLocalAddress();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public InetSocketAddress getDefaultLocalAddress() {
        return (InetSocketAddress) super.getDefaultLocalAddress();
    }

    /**
     * {@inheritDoc}
     */
    public void setDefaultLocalAddress(InetSocketAddress localAddress) {
        setDefaultLocalAddress((SocketAddress) localAddress);
    }

Let's open a socket address:
   /**
     * {@inheritDoc}
     */
    @Override
    protected ServerSocketChannel open(SocketAddress localAddress) throws Exception {
        // Creates the listening ServerSocket
        ServerSocketChannel channel = null;
	//If the selector provider is not empty, open a ServerSocketChannel through the selector provider, otherwise
	//Open a socket channel server through ServerSocketChannel.
        if (selectorProvider != null) {
            channel = selectorProvider.openServerSocketChannel();
        } else {
            channel = ServerSocketChannel.open();
        }
        boolean success = false;
        try {
	    //Configure the channel blocking mode, and the address reuse configuration of the SeverSocket associated with the channel, and then bind the address through the SeverSocket
            // This is a non blocking socket channel
            channel.configureBlocking(false);
            // Configure the server socket,
            ServerSocket socket = channel.socket();
            // Set the reuseAddress flag accordingly with the setting
            socket.setReuseAddress(isReuseAddress());
            // and bind.
            try {
                socket.bind(localAddress, getBacklog());
            } catch (IOException ioe) {
                // Add some info regarding the address we try to bind to the
                // message
                String newMessage = "Error while binding on " + localAddress + "\n" + "original message : "
                        + ioe.getMessage();
                Exception e = new IOException(newMessage);
                e.initCause (ioe.getCause ());

                // And close the channel
                channel.close();

                throw e;
            }
            // Register the channel within the selector for ACCEPT event
            channel.register(selector, SelectionKey.OP_ACCEPT);
            success = true;
        } finally {
            if (!success) {
                close(channel);
            }
        }
        return channel;
    }

From the above point of view, open a socket address. If the selector provider is not empty, open a ServerSocketChannel through the selector provider, otherwise open a socket channel server through ServerSocketChannel; configure the channel blocking mode, and reuse the address of the SeverSocket associated with the channel Configuration, and then bind the address through SeverSocket.
Let's look at receiving connections:
   /**
     * {@inheritDoc}
     */
    @Override
    protected NioSession accept(IoProcessor<NioSession> processor, ServerSocketChannel handle) throws Exception {
        SelectionKey key = null;
	/ / Process serversocketHandler pending selection key
        if (handle != null) {
            key = handle.keyFor(selector);
        }
        if ((key == null) || (!key.isValid()) || (!key.isAcceptable())) {
            return null;
        }
        // accept the connection from the client
	// receive connection
        SocketChannel ch = handle.accept();
        if (ch == null) {
            return null;
        }
        return new NioSocketSession(this, processor, ch);
    }

From the above point of view, the listener accepts the connection, which is actually delegated to the ServerSocketChannel of the binding address, accepts the connection from the client, generates a SocketChannel, and then creates a session according to the SocketChannel and the Io processor.
Let's look at the selection operation again:
 
  /**
     * Check if we have at least one key whose corresponding channels is
     * ready for I/O operations.
     * Check if the channel has the selected key ready for read and write operations
     * This method performs a blocking selection operation.
     * It returns only after at least one channel is selected,
     * this selector's wakeup method is invoked, or the current thread
     * is interrupted, whichever comes first.
     *
     * @return The number of keys having their ready-operation set updated
     * @throws IOException If an I/O error occurs
     * @throws ClosedSelectorException If this selector is closed
     */
    @Override
    protected int select() throws Exception {
        return selector.select();
    }

From the above it looks like the selection operation is actually delegated to the inner selector.
Let's look at other methods
/**
 * {@inheritDoc}
 Get serversocket channel local address
 */
@Override
protected SocketAddress localAddress(ServerSocketChannel handle) throws Exception {
    return handle.socket().getLocalSocketAddress();
}
*
 * {@inheritDoc}
 close the serversocket channel
 */
@Override
protected void close(ServerSocketChannel handle) throws Exception {
    SelectionKey key = handle.keyFor(selector);
    if (key != null) {
        key.cancel();
    }
    handle.close();
}

/**
 * {@inheritDoc}
 wakeup selector
 */
@Override
protected void wakeup() {
    selector.wakeup();
}
 /**
  * {@inheritDoc}
  Get the ServerSocketChannel registered to the selector
  */
 @Override
 protected Iterator<ServerSocketChannel> selectedHandles() {
     return new ServerSocketChannelIterator(selector.selectedKeys());
 }

 /**
  * Defines an iterator for the selected-key Set returned by the
  * selector.selectedKeys(). It replaces the SelectionKey operator.
  */
 private static class ServerSocketChannelIterator implements Iterator<ServerSocketChannel> {
     /** The selected-key iterator */
     private final Iterator<SelectionKey> iterator;

     /**
      * Build a SocketChannel iterator which will return a SocketChannel instead of
      * a SelectionKey.
      *
      * @param selectedKeys The selector selected-key set
      */
     private ServerSocketChannelIterator(Collection<SelectionKey> selectedKeys) {
         iterator = selectedKeys.iterator();
     }

     /**
      * Tells if there are more SockectChannel left in the iterator
      * @return <tt>true</tt> if there is at least one more
      * SockectChannel object to read
      */
     public boolean hasNext() {
         return iterator.hasNext();
     }

     /**
      * Get the next SocketChannel in the operator we have built from
      * the selected-key et for this selector.
      *
      * @return The next SocketChannel in the iterator
      */
     public ServerSocketChannel next() {
         SelectionKey key = iterator.next();

         if (key.isValid() && key.isAcceptable()) {
             return (ServerSocketChannel) key.channel();
         }

         return null;
     }

     /**
      * Remove the current SocketChannel from the iterator
      */
     public void remove() {
         iterator.remove();
     }
}

Summary:
The socket listens to NioSocketAcceptor, and there are two internal variables for selector selector and selector provider selectorProvider. The main job of the init method is to open a selector selector. Open a socket address, if the selector provider is not empty, open a ServerSocketChannel through the selector provider, otherwise open a socket channel server
through ServerSocketChannel; configure the channel blocking mode, and the address reuse configuration of the SeverSocket associated with the channel, then Bind the address through SeverSocket. The listener accepts the connection, which is actually delegated to the ServerSocketChannel of the binding address, accepts the connection from the client, generates a SocketChannel, and then creates a session according to the SocketChannel and the Io handler. The select wakeup operation is actually delegated to the internal selector.


Attached:
//SocketAcceptor
/**
 * {@link IoAcceptor} for socket transport (TCP/IP).  This class
 * handles incoming TCP/IP based socket connections.
 *
 * @author [url=http://mina.apache.org]Apache MINA Project[/url]
 */
public interface SocketAcceptor extends IoAcceptor {
    /**
     * @return the local InetSocketAddress which is bound currently.  If more than one
     * address are bound, only one of them will be returned, but it's not
     * necessarily the firstly bound address.
     * This method overrides the {@link IoAcceptor#getLocalAddress()} method.
     */
    @Override
    InetSocketAddress getLocalAddress();

    /**
     * @return a {@link Set} of the local InetSocketAddress which are bound currently.
     * This method overrides the {@link IoAcceptor#getDefaultLocalAddress()} method.
     */
    @Override
    InetSocketAddress getDefaultLocalAddress();

    /**
     * Sets the default local InetSocketAddress to bind when no argument is specified in
     * {@link #bind()} method. Please note that the default will not be used
     * if any local InetSocketAddress is specified.
     * This method overrides the {@link IoAcceptor#setDefaultLocalAddress(java.net.SocketAddress)} method.
     *
     * @param localAddress The local address
     */
    void setDefaultLocalAddress(InetSocketAddress localAddress);

    /**
     * @see ServerSocket#getReuseAddress()
     *
     * @return <tt>true</tt> if the <tt>SO_REUSEADDR</tt> is enabled
     */
    boolean isReuseAddress();

    /**
     * @see ServerSocket#setReuseAddress(boolean)
     *
     * @param reuseAddress tells if the <tt>SO_REUSEADDR</tt> is to be enabled
     */
    void setReuseAddress(boolean reuseAddress);

    /**
     * @return the size of the backlog.
     */
    int getBacklog();

    /**
     * Sets the size of the backlog.  This can only be done when this
     * class is not bound
     *
     * @param backlog The backlog's size
     */
    void setBacklog(int backlog);

    /**
     * @return the default configuration of the new SocketSessions created by
     * this acceptor service.
     */
    @Override
    SocketSessionConfig getSessionConfig();
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326403849&siteId=291194637