Preface
I have a general understanding of NIO operation and three components
Java network programming (4) NIO understanding and three components of NIO
And learn in detail: Buffer and Channel
Java network programming (5) NIO - Buffer details
Java network programming (6) NIO - Channel details
Next, complete the learning of Selector
Catalog
- Selector function
- Selector class inheritance relationship
- common method
- SelectionKey
- A case of chat system
- summary
Selector function
NIO programming structure:
Selectors enable a thread to handle multiple channels. Selectors poll the channels registered on them. Selectors can only manage non blocking channels. File channels (filechannels, etc.) are blocked and cannot be managed
So Selector is the Selector of network communication channel. The most common operation is to operate ServerSocketChannel and SocketChannel
Selector class inheritance relationship
Selector is an abstract class with many subclasses, among which the implementation class is WindowsSelectorImpl
common method
The Selector itself has these methods:
- instantiation
Because the Selector is an abstract class, that is, it cannot be instantiated with new. To obtain a Selector object through the open() method
Selector selector = Selector.open();
- select()
The select() method monitors all channels registered on the selector. When there is IO operation available, the SelectionKey corresponding to the channel is added to the collection and returned (the SelectionKey is an important object)
- select(long timeout)
Because the select method is blocked, that is, you must wait until an event occurs in a channel, and you can set the TimeOut to unblock - selectNow()
Non blocking select method - selectedKeys()
Get the SelectionKey of the existing event - keys()
The SelectionKey of all registered channels is saved - isOpen()
Determine whether the selector is on - wakeup()
Wake up selector
selector.select() is blocked. Generally, select() will wake up from the block only when the channel registered on the selector has event ready. When the channel on the selector has no ready event, if you want to wake up the blocked thread on the select() operation to handle some other work, you can use the wakeup method
SelectionKey
SelectionKey is an abstract class, and the implementation class is SelectionKeyImpl class
Selectionkey indicates the identity of the SelectableChannel registered in the Selector. When each Channel registers with the Selector, a selectionkey will be created
SelectableChannel is the parent class of various network channels, which can be transformed to the Channel we want
Use
SelectionKey object. This object contains some properties:
- interest set: the selected set of interested events
- Ready set: the set of operations for which the channel is ready
- Channel: SelectionKey can get the marked channel object
- Selector: SelectionKey can get the selector object used
- Additional object (optional): you can attach an object or more information to the SelectionKey, so that you can easily identify a given channel, such as attaching a Buffer
- Operation set
When a channel is registered with a selector, you can select the events to listen to
For example, serverSocketChannel needs to listen for request connection events
//Register, server listens for request connection events serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
Selectionkey.op'accept is an operation set
SelectionKey has four operation sets, which are bitwise operation values:
OP? Read value is 1
Op'write value is 4
OP? Connect is 8
The op? Accept value is 16
interesOps(): get the inter collection of this SelectionKey
interestOps(int ops): set the interest of this SelectionKey to the specified value (previously set at registration time)
- Channel()
Returns the channel associated with this selection key. Even if this key has been cancelled, it will still return
In reading and writing operations, this method is generally used to obtain the Channel through SelectionKey - Selector()
Returns the Selector associated with this selection key - Attached objects: attachment()
You can choose to set a buffer when registering
socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
This reduces the overhead of the buffer, which is then obtained by the attachment method
ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
Of course, it can be set on the SelectionKey
attach(Object ob): add the given object as an attachment to this key
- ready set: judge events
isAcceptable(): judge whether it is a connection event (used by server channel)
isValid(): judge whether the key is valid
isReadable(): check whether the key is a "read" event
A case of chat system
The server
package com.company.Selector.Selector1; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; import java.util.Set; public class NIOServer { public static void main(String[] args) throws Exception { //Open ServerSocketChannel to wait for connection ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //Set non blocking serverSocketChannel.configureBlocking(false); //Binding port number 6666 serverSocketChannel.socket().bind(new InetSocketAddress(6666)); //Open selector Selector selector = Selector.open(); //Register and listen for connection events serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (true){ //Loop monitoring //select is the blocking method /* if ( selector.select(5000)==0){ System.out.println("No client connection '); continue; }*/ selector.select(); //Get the SelectionKey of the existing event Set<SelectionKey> selectionKeys = selector.selectedKeys(); //Iterative Set set Iterator<SelectionKey> keyIterator = selectionKeys.iterator(); while (keyIterator.hasNext()){ SelectionKey key = keyIterator.next(); if (key.isAcceptable()){ System.out.println("Get client connection"); //accept to get SocketChannel SocketChannel socketChannel = serverSocketChannel.accept(); //Set non blocking socketChannel.configureBlocking(false); //Register, socketChannel listens for read events //Associate a bytebuffer //socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024)); socketChannel.register(selector, SelectionKey.OP_READ); } if (key.isReadable()){ //The channel method of SelectionKey to get SocketChannel SocketChannel socketChannel = (SocketChannel) key.channel(); //Get buffer //ByteBuffer byteBuffer = (ByteBuffer) key.attachment(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //Read data from channel socketChannel.read(byteBuffer); byteBuffer.clear(); System.out.println(new String(byteBuffer.array())); } keyIterator.remove(); } } } }
Client
package com.company.Selector.Selector1; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.Scanner; public class NIOClient { public static void main(String[] args) throws Exception{ //Open channel SocketChannel socketChannel = SocketChannel.open(); //Set to non blocking socketChannel.configureBlocking(false); //binding InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 6666); if(!socketChannel.connect(inetSocketAddress)){ while (!socketChannel.finishConnect()){ System.out.println("connection failed"); } } while (true) { Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); System.out.println(str); ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes()); socketChannel.write(byteBuffer); } } }
summary
- Selector is a selector used to handle non blocking channels, that is, a thread can set a selector to handle multiple channels
- Selectors are used to process network channels. The commonly used channels are ServerSocketChannel and SocketChannel. These channels need to be registered on the Selector before they can be managed
- The Selector has many methods, among which the select() method monitors all channels. When there are channel events, the SelectionKey object of the channel will be saved to the collection
- SelectionKey is an identity object, which holds many properties