Nio study notes (most of them are excerpted from the Internet)

Keywords: Java REST

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 }

Posted by jiehuang001 on Mon, 09 Dec 2019 02:51:50 -0800