This is the second day of my participation in the August More Text Challenge

Introduction to selectors

A Selector, commonly known as a Selector, is one of the core components of Java NIO that checks whether the state of one or more NIO channels is readable and writable. It is possible to manage multiple channels with a single thread, that is, manage multiple network links. The selector class manages information about a collection of registered channels and their ready states. Channels are registered with a selector, which is used to update the ready state of the channel. The benefit of Selector is that fewer threads are used to process the channel, avoiding the overhead of thread context switching compared to using multiple threads.

SelectableChannel

Not all channels can be multiplexed by Selector. For example, FileChannel cannot be reused by selectors. To determine whether a Channel can be reused by Selector, one prerequisite is to determine whether it inherits an abstract class, SelectableChannel. SelectableChannel can be reused if it is inherited, but not otherwise.

The SelectableChannel class provides the public methods needed to implement channel selectivity. It is the parent of all channel classes that support readiness checking. All socket channels, which inherit from the SelectableChannel class, are optional, including channels obtained from the Pipe object. The FileChannel class, however, does not inherit SelectableChannel and is therefore not an optional channel. A channel can be registered with more than one selector, but only once for each selector. The relationship between channels and selectors is done using registration. SelectableChannel can be registered with a Selector object, and when you register it, you specify which operations on the channel that the Selector is interested in.

Register a Channel with a Selector

Register a Channel with a Selector using the channel. register (Selector sel, int OPS) method. The first parameter specifies who the selector is for the channel to register. The second parameter specifies the channel operations that the selector needs to query. A Channel must be non-blocking. So a FileChannel is not suitable for Selector, because a FileChannel cannot switch to non-blocking mode, or more precisely because a FileChannel does not inherit SelectableChannel. Socket channel can be used normally. The SelectableChannel abstract class has a configureBlocking () method used to put the channel in blocking or non-blocking mode.

abstract SelectableChannel configureBlocking(boolean block)

SelectableChannel configureBlocking of abstract class () method is implemented by AbstractSelectableChannel abstract classes, SocketChannel, ServerSocketChannel, DatagramChannel is directly inherited AbstractSelectableChannel abstract classes. The second argument to the register() method. This is an “interest set,” meaning what event is of interest when listening to a Channel with Selector. You can listen for four different types of events: Connect, Accept, Read, and Write; The channel raised an event meaning that the event is ready. For example, a Channel that successfully connects to another server is “connection-ready”. A Server Socket Channel that is ready to receive incoming connections is called “receive ready”. A channel with data to read can be said to be “read ready”. A channel waiting to write data can be said to be “write ready”. OP_CONNECT SelectionKey.OP_ACCEPT SelectionKey.OP_READ SelectionKey

If the Selector to channel more interested in operation type, you can use “or” operator to achieve: int. Key = SelectionKey OP_READ | SelectionKey. OP_WRITE;

Select key (SelectionKey)

The selection key encapsulates the registration relationship between a particular channel and a particular selector. Select key object is SelectableChannel. The register () returns and provide a tag says this registered relationship. The select key contains two sets of bits (encoded as integers) that indicate the channel operations that the registry is interested in and that the channel is ready for.

Once the relationship between a Channel and a Selector is established, and the Channel is in some ready state, it can be queried by the Selector. This is done using the select () method of the Selector. The select method is used to query the ready state of the channel operation of interest. Selector can constantly query the ready state of operations that occur in a Channel. And pick the operation ready state of interest. Once a channel has a ready state for an operation, and it’s an operation that the Selector is interested in, it’s selected by the Selector and put into the selection key set.

A SelectionKey, first of all, contains the type of the channel operation registered in the Selector, such as selectionkey.op_read. It also contains registration relationships between specific channels and specific selectors. Selecting keys during development is the key to programming. NIO programming, is according to the corresponding selection key, different business logic processing. A SelectionKey represents the registration relationship between a particular channel object and a particular selector object.

key.attachment(); // Return the attachment of SelectionKey, which can be specified when registering a channel.

key.channel(); // Return the channel corresponding to the SelectionKey.

key.selector(); // Returns the Selector corresponding to the SelectionKey.

key.interestOps(); // Returns a bit mask representing the I/O operation to be monitored by Selector

key.readyOps(); // Return a bit mask representing the IO operations that can be performed on the corresponding channel.

key.interestOps():

You can tell if a Selector is interested in an event of a Channel by using the following method

int interestSet = selectionKey.interestOps(); Boolean isInterestedInAccept = (interestSet & selectionkey.op_ACCEPT) == selectionkey.op_accept; boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT; boolean isInterestedInRead = interestSet & SelectionKey.OP_READ; boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE; The key.readyops () ready collection is a collection of operations for which the channel is ready. The following methods are defined in JAVA to check that these operations are ready.

Int readySet = selectionKey.readyops (); Method of checking whether these operations are acceptable key.isacceptable (); Boolean isWritable() : // whether it isWritable, true Boolean isConnectable() : // whether it isConnectable, true Boolean isAcceptable() : // Whether it can be received, if true

The flow of using Selector

Create a Selector

The Selector object is instantiated by calling the static factory method open(), as follows:

Selector = Selector. Open (); Internally, the Selector class method open() makes a request to the SPI to get a new instance through the default SelectorProvider object. To manage a Channel, you need to register a Channel with the corresponding Selector, as follows: ServerSocketChannel ServerSocketChannel = ServerSocketChannel.open(); / / set to non-blocking serverSocketChannel. ConfigureBlocking (false); Bind (new InetSocketAddress(systemconfig.socket_server_port)); // Bind to serversocketChannel. bind(new InetSocketAddress(systemconfig.socket_server_port)); / / register a channel to the selector, and set to monitor events as: "receive" event serverSocketChannel. Register (selector, SelectionKey. OP_ACCEPT);Copy the code

The channel’s register() method above registers it with a selector.

Note: when used with the Selector must Channel is in non-blocking mode, otherwise will throw an exception IllegalBlockingModeException. That is, a FileChannel cannot be used with a Selector because a FileChannel cannot switch to non-blocking mode, whereas all channels associated with a socket can.

In addition, a channel does not have to support all four operations. For example, ServerSocketChannel supports the Accept operation, while SocketChannel client does not. You can retrieve the set of all supported operations for a particular channel by using the validOps() method on the channel.

Polling query ready operation

The next step is the query-ready operation. The Selector select () method is used to query the Set of ready channel operations in a Set whose elements are SelectionKey objects.

Here are a few query select() methods:

Select (): blocks until at least one channel is ready on the event you registered.

Select (long timeout) : Same as select(), but the longest blocking event is timeout milliseconds.

SelectNow (): non-blocking, returns as soon as a channel is ready.

The int returned by the select() method indicates how many channels are ready, or more precisely, how many channels have become ready in the time period between the previous select method and the current select method.

The next step is to access the set of selectedKeys by calling Selector’s selectedKeys() method and iterating over each selected key element of the set, depending on the type of ready action:

Set selectedKeys = selector.selectedKeys(); Iterator keyIterator = selectedKeys.iterator(); while(keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if(key.isAcceptable()) { // a connection was accepted by a ServerSocketChannel. } else if (key.isConnectable()) { // a connection was established with a remote server. } else if (key.isReadable()) { // a channel is ready for reading } else  if (key.isWritable()) { // a channel is ready for writing } keyIterator.remove(); }Copy the code

Once the process is complete, the selection key is removed directly from the set to prevent it from being processed again in the next loop. Keys can but cannot be added. To a collection of selected key element is added will throw Java lang. UnsupportedOperationException.