The previous two articles introduced buffers and channels in NIO. With that in mind, this article introduces another important concept —-Selector. We know that switching system threads consumes system resources, and if we were to manage each connection with a single thread, that resource would be too expensive, so we could use Selector. A thread can manage multiple channels with Selector, as shown in the following figure:

The Selector using

Open the

You get a Selector object before you use it

Selector selector = Selector.open();
Copy the code

registered

To register a Channel with a Selector, it must be non-blocking. So a FileChannel can’t register a Selector. If the registration is not call configureBlocking method will be thrown IllegalBlockingModeException anomalies.

SelectionKey

There are four kinds of selectionkeys

  • OP_ACCEPT
  • OP_CONNECT
  • OP_WRITE
  • OP_READ

ServerSocketChannel registered

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
Copy the code

The Operation Set of ServerSocketChannel must be OP_ACCEPT. If OP_CONNECT, OP_WRITE, or OP_READ is added during registration, an exception is reported. For example, write as follows

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT | SelectionKey.OP_CONNECT);
Copy the code

The following exception is thrown

Exception in thread "main" java.lang.IllegalArgumentException
	at java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSelectableChannel.java:199)
	at java.nio.channels.SelectableChannel.register(SelectableChannel.java:280)
	at com.nio.sample.selector.SelectorServerSocketChannelSample.main(SelectorServerSocketChannelSample.java:27)
Copy the code

ServerSocketChannel validOps can see that only OP_ACCEPT is valid

public final int validOps() {
    return SelectionKey.OP_ACCEPT;
}
Copy the code

SocketChannel registered

socketChannel.register(selector, SelectionKey.OP_CONNECT);
Copy the code

The Operation Set of a SocketChannel can only be OP_CONNECT, OP_WRITE, or OP_READ. If OP_ACCEPT is added during SocketChannel registration, an exception is also reported.

SocketChannel validOps can see that only OP_READ, OP_WRITE, and OP_CONNECT are valid

public final int validOps() {
    return (SelectionKey.OP_READ
            | SelectionKey.OP_WRITE
            | SelectionKey.OP_CONNECT);
}
Copy the code

After successful registration, we implement a demo, where the client and server interact:

Server:

public static void main(String[] args) throws Exception {

	ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

	serverSocketChannel.socket().bind(new InetSocketAddress(9000));
	serverSocketChannel.configureBlocking(false); Selector selector = Selector.open(); // configureBlocking Register when abnormal transactions / / Java nio. Channels. IllegalBlockingModeException serverSocketChannel. Register (selector, SelectionKey.OP_ACCEPT);while (true) {

		int selected = selector.select();
		
		if (selected > 0) {

			Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
			while (iterator.hasNext()) {

				SelectionKey selectionKey = iterator.next();
				iterator.remove();

				if (selectionKey.isAcceptable()) {
					System.err.println("Acceptable");
					SocketChannel socketChannel = serverSocketChannel.accept();
					socketChannel.configureBlocking(false);
					socketChannel.register(selector, SelectionKey.OP_READ);
				} else if (selectionKey.isReadable()) {
					System.err.println("Readable");
					SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
					ByteBuffer buffer = ByteBuffer.allocate(128);
					socketChannel.read(buffer);
					System.out.println("Receive data from client:" + new String(buffer.array()));
					selectionKey.interestOps(SelectionKey.OP_WRITE);
				} else if (selectionKey.isWritable()) {
					System.err.println("Writable");
					SocketChannel channel = (SocketChannel) selectionKey.channel();
					String content = "Send data to client:" + System.currentTimeMillis();
					ByteBuffer buffer = ByteBuffer.wrap(content.getBytes());
					channel.write(buffer);
					selectionKey.interestOps(SelectionKey.OP_READ);
				}
			}
		}
	}
}
Copy the code

Let’s look at the logic on the server side

1. The server registers the selector, then sets the interest set (OPS) to selectionKey. OP_ACCEPT and waits for the client to connect.

2, client connection to arrive, call to selectionKey. IsAcceptable () method, receiving client connection, and then get a channel, and place

Interest set to selectionKey. OP_READ Waits for data to be read from the channel.

InterestOps = selectionKey.op_write selectionKey.interestOps = selectionkey.op_write selectionKey.interestOps = selectionkey.op_write

InterestOps selectionKey.isWritable() is triggered to send data to the client, and selectionKey.interestOps is set again to

Selectionkey. OP_READ Waits for client data to arrive.

Client:

public static void main(String[] args) throws IOException {

	SocketChannel socketChannel = SocketChannel.open();

	socketChannel.configureBlocking(false);
	Selector selector = Selector.open();
	socketChannel.register(selector, SelectionKey.OP_CONNECT);

	socketChannel.connect(new InetSocketAddress("127.0.0.1", 9000));

	while (true) {
		int select = selector.select();

		if (select > 0) {

			Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
			while (iterator.hasNext()) {

				SelectionKey selectionKey = iterator.next();

				if (selectionKey.isConnectable()) {
					System.err.println("Connectable");
					SocketChannel clientChannel = (SocketChannel) selectionKey.channel();
					clientChannel.finishConnect();
					selectionKey.interestOps(SelectionKey.OP_WRITE);

				} else if (selectionKey.isReadable()) {
					System.out.println("Readable");
					SocketChannel channel = (SocketChannel) selectionKey.channel();
					ByteBuffer buffer = ByteBuffer.allocate(128);
					channel.read(buffer);
					selectionKey.interestOps(SelectionKey.OP_WRITE);
					System.out.println("Received server data" + new String(buffer.array()));

				} else if (selectionKey.isWritable()) {
					SocketChannel clientChannel = (SocketChannel) selectionKey.channel();
					String str = "qiwoo mobile";
					ByteBuffer buffer = ByteBuffer.wrap(str.getBytes());
					clientChannel.write(buffer);
					selectionKey.interestOps(SelectionKey.OP_READ);
					System.out.println("Send data to the server"+ new String(buffer.array())); } iterator.remove(); }}}}Copy the code

Take a look at the logic on the server side

1. Send a connection request to the server.

2, selectionKey. IsConnectable () is triggered, the connection is successful, selectionKey. InterestOps set to selectionKey. OP_WRITE, ready to send data to the server.

InterestOps is set to selectionKey. OP_READ and waits for the data to come from the server.

InterestOps: selectionKey.op_write SelectionKey.op_write SelectionKey.op_write selectionKey.op_write selectionKey.op_write

Pay attention to wechat public number, the latest technology dry goods real-time push