Differences between Nio and IO
The original IO is flow oriented and blocking, while NIO is block oriented and non blocking.
1. Each time an IO stream reads one or more bytes from the stream until all the bytes are read, they are not cached in other places. In addition, the IO stream cannot move the data in the stream. If it is necessary to move the data read from the stream back and forth, it needs to be cached in a buffer first. Java NIO's buffer oriented approach is slightly different. The data is read to a buffer which it will process later. It can move back and forth in the buffer if necessary. This increases the flexibility of the process. However, you also need to check that the buffer contains all the trains that you need to process. Also, make sure that when more data is read into the buffer, do not overwrite the unprocessed data in the buffer.
2. Various streams of Java IO are blocked. This means that when a thread calls read() or write(), the thread is blocked until some data is read or fully written. The thread cannot do anything more during this time. The non blocking mode of Java NIO enables a thread to send a request to read data from a channel, but it can only get the data currently available. If there is no data available at present, nothing will be obtained. Instead of keeping the thread blocked, the thread can continue to do other things until the data becomes readable. The same is true for non blocking writes. A thread requests to write some data to a channel, but does not need to wait for it to write completely. This thread can do other things at the same time. Threads usually use non blocking IO idle time to perform IO operations on other channels, so a single thread can now manage multiple input and output channels. ,
Channel
The channel of NIO is similar to flow, but there are some differences as follows:
1. Channels can read and write at the same time, while streams can only read or write
2. The channel can read and write data asynchronously
3. The channel can read data from buffer or write data to buffer:
Buffer class
Buffer is an object, which has four basic attributes. Nio's reading and writing are realized by buffer. In short, read data is read from buffer first, and write data is written to buffer first. The most commonly used implementation class is ByteBuffer. There is a corresponding buffer implementation class for basic types in Java, such as CharBuffer,DoubleBuffer, etc
1. The meanings of the four attributes are as follows:
Capacity: the maximum number of data elements that a buffer can hold. This capacity is set when the buffer is created and can never be changed.
Limit: the first element of a buffer that cannot be read or written. Or, the count of existing elements in the buffer.
Position: the index of the next element to be read or written. The location is automatically updated by the corresponding get() and put() functions.
Mark: the index of the next element to be read or written. The location is automatically updated by the corresponding get() and put() functions.
The common methods of Buffer are as follows:
flip(): write mode converted to read mode
rewind(): reset the position to 0, which is generally used for repeated reading.
clear() :
compact(): copy the unread data to the header of the buffer.
mark(): reset():mark can mark a location, reset can reset to that location
3. Read operation
1 FileInputStream inputStream = new FileInputStream("E:\\A.txt"); 2 /** 3 * Get access 4 */ 5 FileChannel channel = inputStream.getChannel(); 6 7 /** 8 * Create cache 9 */ 10 ByteBuffer buffer = ByteBuffer.allocate(1024); 11 12 /** 13 * Read data to buffer 14 */ 15 channel.read(buffer); 16 17 buffer.flip(); 18 19 while (buffer.remaining() > 0){ 20 byte b = buffer.get(); 21 System.out.println(((char)b)); 22 } 23 /** 24 * Closed flow 25 */ 26 inputStream.close();
Write operation
1 static private final byte message[] = { 83,83,83,83,83,83 }; 2 3 static public void main( String args[] ) throws Exception { 4 FileOutputStream fout = new FileOutputStream( "e:\\A.txt" ); 5 6 FileChannel fc = fout.getChannel(); 7 8 ByteBuffer buffer = ByteBuffer.allocate( 1024 ); 9 10 for (int i=0; i<message.length; ++i) { 11 buffer.put( message[i] ); 12 } 13 14 buffer.flip(); 15 16 fc.write( buffer ); 17 18 fout.close(); 19 }
Selector
Multiple NiO channels can be detected to see if the read or write events are ready. Multiple channels can be registered to the same Selector as events, making it possible to process multiple requests with one thread.
There are three steps to write a server handler using nonblocking IO in NIO
1. Register the event of interest with the Selector object
2. Get events of interest from the Selector
3. Carry out corresponding handling according to different events
Brief API introduction
open: create selector
Select keys: get the collection of available channel s
Select: select ready channels
Simple chat room realization thought code
Server code
1 public class NioServer { 2 3 4 public void start() throws Exception { 5 /** 6 * 1.Create selector 7 */ 8 Selector selector = Selector.open(); 9 /** 10 * 2.Create channel through ServerSocketChannel 11 */ 12 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 13 14 /** 15 * 3.Binding listening port for channel channel 16 */ 17 serverSocketChannel.bind(new InetSocketAddress(8000)); 18 /** 19 * 4.Set channel to non blocking mode 20 */ 21 serverSocketChannel.configureBlocking(false); 22 /** 23 * 5.Register channel to selector and listen for connection 24 */ 25 serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT); 26 System.out.println("Server started successfully"); 27 /** 28 * 6.Loop waiting for new connections 29 */ 30 for(;;){ 31 int select = selector.select(); 32 if (select == 0){ 33 continue; 34 } 35 36 /** 37 * 7.Get a collection of available channel s 38 */ 39 Set<SelectionKey> keys = selector.selectedKeys(); 40 Iterator<SelectionKey> iterator = keys.iterator(); 41 while (iterator.hasNext()){ 42 SelectionKey selectionKey = (SelectionKey) iterator.next(); 43 /** 44 * 8.Remove selctionKey 45 */ 46 iterator.remove(); 47 /** 48 * Handling specific business logic 49 */ 50 /** 51 * Access event 52 */ 53 if (selectionKey.isAcceptable()){ 54 acceptHandler(serverSocketChannel,selector); 55 } 56 /** 57 * Readable event 58 */ 59 if(selectionKey.isReadable()){ 60 readHandler(selectionKey, selector); 61 } 62 } 63 64 65 } 66 67 68 /** 69 * According to the ready state, call the corresponding method to process the business logic 70 */ 71 72 } 73 74 /** 75 * Access event processor 76 */ 77 private void acceptHandler(ServerSocketChannel serverSocketChannel, Selector selector) throws Exception { 78 /** 79 * If it is an access event, create a serverSocket 80 */ 81 SocketChannel socketChannel = serverSocketChannel.accept(); 82 /** 83 * Set non blocking 84 */ 85 socketChannel.configureBlocking(false); 86 /** 87 * Register in selector 88 */ 89 socketChannel.register(selector, SelectionKey.OP_READ); 90 /** 91 * Reply to server information 92 */ 93 socketChannel.write(Charset.forName("UTF-8").encode("You're not friends with the rest of the room,Please pay attention to privacy")); 94 95 } 96 97 private void readHandler(SelectionKey selectionKey, Selector selector) throws Exception{ 98 /** 99 * To get the ready channel in selectionKey 100 */ 101 SocketChannel channel = (SocketChannel)selectionKey.channel(); 102 /** 103 * Create buffer 104 */ 105 ByteBuffer buffer = ByteBuffer.allocate(1024); 106 /** 107 * Loop read client data 108 */ 109 String request = ""; 110 while (channel.read(buffer) > 0){ 111 /** 112 * Toggle read mode 113 */ 114 buffer.flip(); 115 /** 116 * Read the contents of buffer 117 */ 118 request += Charset.forName("UTF-8").decode(buffer); 119 120 } 121 /** 122 * channel registration to selector 123 */ 124 channel.register(selector, SelectionKey.OP_READ); 125 /** 126 * Talk about the request information sent by the client and broadcast it to other clients 127 */ 128 if (request.length() > 0){ 129 broadCast(selector, channel, request); 130 } 131 } 132 133 private void broadCast(Selector selector, SocketChannel socketChannel, String request){ 134 /** 135 * Get the access client channel 136 */ 137 Set<SelectionKey> selectionKeys = selector.keys(); 138 selectionKeys.forEach(selectionKey -> { 139 Channel channel = selectionKey.channel(); 140 if (channel instanceof SocketChannel && 141 channel != socketChannel){ 142 try { 143 //Send information to channel Client 144 ((SocketChannel) channel).write(Charset.forName("UTF-8").encode(request)); 145 } catch (IOException e) { 146 e.printStackTrace(); 147 } 148 } 149 }); 150 /** 151 * Loop information to all channel s 152 */ 153 } 154 /** 155 * 156 * @param args 157 */ 158 public static void main(String[] args) throws Exception { 159 NioServer server = new NioServer(); 160 server.start(); 161 } 162 }
Client code
1 public class NioClient { 2 3 4 public void start() throws Exception { 5 /** 6 * Connect to server 7 */ 8 SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8000)); 9 /** 10 * Receiving server address 11 */ 12 Selector selector = Selector.open(); 13 socketChannel.configureBlocking(false); 14 socketChannel.register(selector, SelectionKey.OP_READ); 15 new Thread(new NioClientHandler(selector)).start(); 16 /** 17 * Send data to server 18 */ 19 Scanner scanner = new Scanner(System.in); 20 while (scanner.hasNextLine()){ 21 String next = scanner.nextLine(); 22 if (StringUtils.isNotBlank(next)){ 23 socketChannel.write(Charset.forName("UTF-8").encode(next)); 24 } 25 } 26 } 27 28 public static void main(String[] args) throws Exception { 29 new NioClient().start(); 30 } 31 }
Client thread class
1 public class NioClientHandler implements Runnable { 2 3 private Selector selector; 4 5 public NioClientHandler(Selector selector) { 6 this.selector = selector; 7 } 8 9 @Override 10 public void run() { 11 /** 12 * Loop waiting for new connections 13 */ 14 try { 15 for(;;){ 16 int select = 0; 17 select = selector.select(); 18 19 if (select == 0){ 20 continue; 21 } 22 23 /** 24 * Get a collection of available channel s 25 */ 26 Set<SelectionKey> keys = selector.selectedKeys(); 27 Iterator<SelectionKey> iterator = keys.iterator(); 28 while (iterator.hasNext()){ 29 SelectionKey selectionKey = (SelectionKey) iterator.next(); 30 /** 31 * Remove selctionKey 32 */ 33 iterator.remove(); 34 /** 35 * Readable event 36 */ 37 if(selectionKey.isReadable()){ 38 readHandler(selectionKey, selector); 39 } 40 } 41 } 42 } catch (Exception e) { 43 e.printStackTrace(); 44 } 45 46 47 } 48 49 private void readHandler(SelectionKey selectionKey, Selector selector) throws Exception{ 50 /** 51 * To get the ready channel in selectionKey 52 */ 53 SocketChannel channel = (SocketChannel)selectionKey.channel(); 54 /** 55 * Create buffer 56 */ 57 ByteBuffer buffer = ByteBuffer.allocate(1024); 58 /** 59 * Loop read client data 60 */ 61 String request = ""; 62 while (channel.read(buffer) > 0){ 63 /** 64 * Toggle read mode 65 */ 66 buffer.flip(); 67 /** 68 * Read the contents of buffer 69 */ 70 request += Charset.forName("UTF-8").decode(buffer); 71 72 } 73 /** 74 * channel registration to selector 75 */ 76 channel.register(selector, SelectionKey.OP_READ); 77 /** 78 * Talk about the request information sent by the client and broadcast it to other clients 79 */ 80 if (request.length() > 0){ 81 System.out.println(request); 82 } 83 } 84 }