java.nio.channels.Selector Example
This example shows the basic usage of Selector
. This is an abstract class defined in the java.nio.channels
package.
Selector
is a multiplexor of SelectableChannel
objects.
NOTE: From the thefreedictionary.com a data-multiplexer is defined as a multiplexer that permits two or more data sources to share a common transmission medium.
Multiplexed, non-blocking I/O, which is much more scalable than thread-oriented, blocking I/O, is provided by the classes Selector
, SelectableChannel
, and SelectionKey
. A SelectableChannel
can be multiplexed via a selector. DatagramChannel
, Pipe.SinkChannel
, Pipe.SourceChannel
, ServerSocketChannel
and SocketChannel
classes extend SelectableChannel
.
Description
- A selector is a multiplexor of selectable channels, which in turn are a special type of channel that can be put into non-blocking mode.
- To perform multiplexed I/O operations, one or more selectable channels are first created, put into non-blocking mode, and registered with a selector.
- Registering a channel specifies the set of I/O operations that will be tested for readiness by the selector, and returns a selection key that represents the registration.
- Once some channels have been registered with a selector, a selection operation can be performed in order to discover which channels, if any, have become ready to perform one or more of the operations in which interest was previously declared.
- If a channel is ready then the key returned when it was registered will be added to the selector’s selected-key set.
- The key set, and the keys within it, can be examined in order to determine the operations for which each channel is ready. From each key one can retrieve the corresponding channel in order to perform whatever I/O operations are required.
1. The Example
This example uses ServerSocketChannel
and SocketChannel
classes to define server and client. The example has two programs; a main program which defines the server socket channel and the selector, and a client socket channel program.
The main program code is explained here:
1.1. Create a selector
Selector selector = Selector.open();
The selector is created by invoking the open()
static method of the selector class.
1.2. Open a server socket channel
ServerSocketChannel serverSocket = ServerSocketChannel.open(); InetSocketAddress hostAddress = new InetSocketAddress("localhost", 5454); serverSocket.bind(hostAddress);
1.3. Register the channel with the selector
First, set this channel to non-blocking mode.
serverSocket.configureBlocking(false);
Next, get the server socket channel’s supported operations.
int ops = serverSocket.validOps();
The server socket channel’s validOps()
method returns an operation set identifying this channel’s supported operations i.e., accepting new connections. The SelectionKey
class has variables defining the operation sets. The OP_ACCEPT (socket-accept operation) is the only valid value for server socket channel.
Register this channel with the given selector, returning a SelectionKey
. Selection key is a token representing the registration of a selectable channel with a selector.
SelectionKey selectKy = serverSocket.register(selector, ops, null); // null for an attachment object
1.4. The selection process
The selector’s select()
method selects a set of keys whose corresponding channels are ready for I/O operations. This method performs a blocking 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.
The selectedKeys()
method returns this selector’s selected-key set. The key set, and the keys within it, can be examined in order to determine the operations for which each channel is ready. From each key one can retrieve the corresponding channel in order to perform whatever I/O operations are required.
int noOfKeys = selector.select(); Set selectedKeys = selector.selectedKeys(); Iterator iter = selectedKeys.iterator(); while (iter.hasNext()) { SelectionKey ky = iter.next(); if (ky.isAcceptable()) { // Accept the new client connection SocketChannel client = serverSocket.accept(); client.configureBlocking(false); // Add the new connection to the selector client.register(selector, SelectionKey.OP_READ); } else if (ky.isReadable()) { // Read the data from client SocketChannel client = (SocketChannel) ky.channel(); ...
2. The Code
2.1. The main program
SelectorExample.java
import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.Selector; import java.nio.channels.SelectionKey; import java.nio.ByteBuffer; import java.io.IOException; import java.util.Set; import java.util.Iterator; import java.net.InetSocketAddress; public class SelectorExample { public static void main (String [] args) throws IOException { // Get selector Selector selector = Selector.open(); System.out.println("Selector open: " + selector.isOpen()); // Get server socket channel and register with selector ServerSocketChannel serverSocket = ServerSocketChannel.open(); InetSocketAddress hostAddress = new InetSocketAddress("localhost", 5454); serverSocket.bind(hostAddress); serverSocket.configureBlocking(false); int ops = serverSocket.validOps(); SelectionKey selectKy = serverSocket.register(selector, ops, null); for (;;) { System.out.println("Waiting for select..."); int noOfKeys = selector.select(); System.out.println("Number of selected keys: " + noOfKeys); Set selectedKeys = selector.selectedKeys(); Iterator iter = selectedKeys.iterator(); while (iter.hasNext()) { SelectionKey ky = iter.next(); if (ky.isAcceptable()) { // Accept the new client connection SocketChannel client = serverSocket.accept(); client.configureBlocking(false); // Add the new connection to the selector client.register(selector, SelectionKey.OP_READ); System.out.println("Accepted new connection from client: " + client); } else if (ky.isReadable()) { // Read the data from client SocketChannel client = (SocketChannel) ky.channel(); ByteBuffer buffer = ByteBuffer.allocate(256); client.read(buffer); String output = new String(buffer.array()).trim(); System.out.println("Message read from client: " + output); if (output.equals("Bye.")) { client.close(); System.out.println("Client messages are complete; close."); } } // end if (ky...) iter.remove(); } // end while loop } // end for loop } }
2.1. The client program
SocketClientExample.java
import java.nio.channels.SocketChannel; import java.nio.ByteBuffer; import java.io.IOException; import java.net.InetSocketAddress; public class SocketClientExample { public static void main (String [] args) throws IOException, InterruptedException { InetSocketAddress hostAddress = new InetSocketAddress("localhost", 5454); SocketChannel client = SocketChannel.open(hostAddress); System.out.println("Client sending messages to server..."); // Send messages to server String [] messages = new String [] {"Time goes fast.", "What now?", "Bye."}; for (int i = 0; i < messages.length; i++) { byte [] message = new String(messages [i]).getBytes(); ByteBuffer buffer = ByteBuffer.wrap(message); client.write(buffer); System.out.println(messages [i]); buffer.clear(); Thread.sleep(3000); } client.close(); } }
3. The Output
The main program is started first and then the client program (use two terminals).
3.1. The main program output
Selector open: true Waiting for select... Number of selected keys: 1 Accepted new connection from client: java.nio.channels.SocketChannel[connected local=/127.0.0.1:5454 remote=/127.0.0.1:50686] Waiting for select... Number of selected keys: 1 Message read from client: Time goes fast. Waiting for select... Number of selected keys: 1 Message read from client: What now? Waiting for select... Number of selected keys: 1 Message read from client: Bye. Client messages are complete; close. Waiting for select...
From the output:
- Accepted new connection from client: java.nio.channels.SocketChannel[connected local=/127.0.0.1:…]: This message is displayed after the client program is started. This shows the client connection is accepted by the server.
- Message read from client: Time goes fast. This shows the earlier accepted client’s first message is read.
3.2. The client program output
Client sending messages to server... Time goes fast. What now? Bye.
4. Download Java Source Code
This was an example of java.nio.channels.Selector
You can download the full source code of this example here: SelectorExamples.zip