Netty foundation java NIO
Selector
Three elements: Selector, SelectableChannel, selectable channel and SelectionKey
In essence, the Selector is a listener that monitors whether the channel is generated by operations we care about. The operations correspond to events (connect, receive, read / write). The SelectionKey is used to represent specific events. When the channel is selectable, the channel is registered in the Selector. At this time, the Selector maintains the correlation between the channel and events.
Selector, which manages the set of registered channels and their status SelectableChannel is an abstract class that provides the api that channels can be selected and implemented. FileChannel is not selectable. All Socket related channels are selectable Can a channel be registered on multiple selectors? tolerable Multiple channels can be registered on a selector, but a channel can only be registered once in a selector
SelectionKey encapsulates the events to be monitored, including connection, receiving, reading and writing. On the one hand, the Selector cares about which events the channel will handle On the other hand, when an event is triggered, which events will the channel handle
Use NIO to realize the communication between server and clinet (without selector)
Server
public static void main(String[] args) throws Exception { //Create a server channel and use open to obtain ServerSocketChannel ServerChannel = ServerSocketChannel.open(); //Set ip and port number SocketAddress address = new InetSocketAddress("127.0.0.1", 4321); //socket bound to service channel ServerChannel.socket().bind(address); //Waiting for client connection SocketChannel socketChannel = ServerChannel.accept(); // The data is processed through the buffer ByteBuffer writebuffer = ByteBuffer.allocate(128); writebuffer.put("hello client i am server".getBytes()); writebuffer.flip(); socketChannel.write(writebuffer); // Read data from client ByteBuffer readbuffer = ByteBuffer.allocate(128); StringBuffer stringBuffer = new StringBuffer(); socketChannel.read(readbuffer); readbuffer.flip(); while (readbuffer.hasRemaining()) { stringBuffer.append((char) readbuffer.get()); } System.out.println("client data :" + stringBuffer.toString()); socketChannel.close(); ServerChannel.close(); }
client
public static void main(String[] args) throws Exception { //Open a socket channel SocketChannel socketChannel = SocketChannel.open(); //Set ip and port number SocketAddress address = new InetSocketAddress("127.0.0.1", 4321); //Connect to this address socketChannel.connect(address); // Write before read // The data is processed through the buffer ByteBuffer writebuffer = ByteBuffer.allocate(128); writebuffer.put("hello server i am client ".getBytes()); writebuffer.flip(); socketChannel.write(writebuffer); // Read data from client ByteBuffer readbuffer = ByteBuffer.allocate(128); StringBuffer stringBuffer = new StringBuffer(); socketChannel.read(readbuffer); readbuffer.flip(); while (readbuffer.hasRemaining()) { stringBuffer.append((char) readbuffer.get()); } System.out.println("server data :" + stringBuffer.toString()); socketChannel.close(); }
We don't use a selector here. Next, we write a Nio selector server to compare and learn
Nio selector server
In SelectionKey, we often judge several operation types
- isAcceptable(): Connect
- isConnectable(): ready
- isReadable(): read
- isWritable(): write
Code execution and writing details: see notes
public static void main(String[] args) throws Exception { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //Set ip and port number SocketAddress address = new InetSocketAddress("127.0.0.1", 4321); //socket bound to service channel serverSocketChannel.socket().bind(address); // Set this channel to non blocking serverSocketChannel.configureBlocking(false); // Open a selector Selector selector = Selector.open(); // Register the channel to the selector where the selector is declared to listen for events // Generally speaking, we listen for connection events serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); /* * Manage channels through selectors * Need to know whether the monitored channel is triggered by an event * When the return value of the select method is > 0, it indicates how many operations need to be processed * So we need to keep polling whether it has time to process * */ while (true) { int ready = selector.select(); if (ready == 0) { continue; } // Get the operation collection through the Selected keys Set<SelectionKey> set = selector.selectedKeys(); Iterator<SelectionKey> iterator = set.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); // In order to avoid duplication of operations, we process one and remove one iterator.remove(); //We use the method in the key to determine what operation to handle /* * isAcceptable() : connect * isConnectable() : be ready * isReadable() : read * isWritable() : write in * */ if (key.isAcceptable()) { //Handling accpt events //Get the client connection and register the write event SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); // After processing the connection status, subsequent write operations are added to the selection socketChannel.register(selector, SelectionKey.OP_WRITE); } else if (key.isWritable()) { // After processing the connection, we can use the key to obtain the corresponding event channel SocketChannel socketChannel = (SocketChannel) key.channel(); //Handling write events ByteBuffer writebuffer = ByteBuffer.allocate(128); writebuffer.put("hello client i am server from 4321".getBytes()); writebuffer.flip(); socketChannel.write(writebuffer); //We can register the next events in this channel through the key key.interestOps(SelectionKey.OP_READ); } else if (key.isReadable()) { //Handling read events SocketChannel socketChannel = (SocketChannel) key.channel(); // Read data from client ByteBuffer readbuffer = ByteBuffer.allocate(128); //Read data int read = socketChannel.read(readbuffer); //read = -1 means you have finished reading if (read == -1) { key.cancel(); } //Refresh buffer readbuffer.flip(); //Use string buffer to splice the read data StringBuffer stringBuffer = new StringBuffer(); while (readbuffer.hasRemaining()) { stringBuffer.append((char) readbuffer.get()); } System.out.println("client data :" + stringBuffer.toString()); } else if (key.isConnectable()) { } } } }
[usage]
a. First, obtain the channel through the open method and set the channel to non blocking b. Obtain the selector through the open method, register the channel into the selector, and set the event to be processed by the channel (OP_ACCEPT) c. Polling selector, is there any operation to process currently? Select() > 0? If so, to get the Set of operations to be processed and traverse When traversing the SelectionKey, judge the corresponding operation, and set different processing methods for different operations Such as OP_ACCEPT, receive and register the client channel, and listen for subsequent events, such as OP_WRITE Such as OP_WRITE: obtain the channel itself through the key method, read the data and continue to listen to events, such as OP_READ