This article mainly brings you NIO related knowledge points, some basic theoretical knowledge, consolidate your understanding of NIO. All right, let’s cut to the chase.
One: NIO foundation
What is NIO?
NIO:non-blocking IO is also called new IO non-blocking IO
The three components of NIO
1. Channel
&Buffer
Channel:
- Basic Concepts:
A Channel is similar to a stream. It is a two-way Channel for reading and writing data. Data can be read into buffer or written into a Channel, while the previous stream is either input or output
Create Channel:
- FileChannel (data transfer channel for files)
- DataGramChannel (UDP network programming data transfer channel)
- SockeChannel (data transfer channel can be used by clients and servers for TCP programming)
- ServerSocketChannel (TCP programming data transfer channel dedicated to the server)
- .
Buffer
- Basic Concepts:
Buffers are used to Buffer read and write data.
Common Buffer
- ByteBuffer
- MappedByteBuffer
- DirectByteBuffer
- HeapByteBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
- CharBuffer
2. Selector
- Multi-threaded edition design:
⚠️ Multithreaded version disadvantages
High memory footprint The high cost of thread context switching is only suitable for scenarios with a small number of connections
- Thread pool version design
⚠️ Thread pool version disadvantages
In blocking mode, the thread can process only one socket connection only for short connection scenarios
The selector version
The design of the
Basic concepts of selectorAnd what a selector does is it matchesA thread
To manage theMultiple channel
, gets events that occur on these channels, which operate in non-blocking mode and do not allow threads to hang on a channel. Suitable for evenThere are too many connections
, butLow traffic
The scenario (low traffic
)
Roughly as shown in the figure:
Select (), which calls selector, blocks until a channel has an access-ready event, which the select method returns to the thread for processing.
Small demo of Channel and Buffer
Channel fetch (FileChannel fetch)
- Indirectly, through the input and output streams,
- Through the randomAccessFile
Obtain ByteBuffer
Allocate (16) by static method bytebuffer.allocate (16)
- TestByteBuffer
@Slf4j
public class TestByteBuffer {
public static void main(String[] args) {
// FileChannel
// 1. Input/output streams,
// 2. RandomAccessFile
// RandomAccessFile file = new RandomAccessFile("helloword/data.txt", "rw")
try (FileChannel channel = new FileInputStream("data.txt").getChannel()) {
// Prepare the buffer
ByteBuffer buffer = ByteBuffer.allocate(10);
while(true) {
// Reads data from channel and writes to buffer
int len = channel.read(buffer);
log.debug("Bytes read {}", len);
if(len == -1) { // There is no more content
break;
}
// Prints the contents of buffer
buffer.flip(); // Switch to read mode
while(buffer.hasRemaining()) { // Check whether there is any unread data
byte b = buffer.get();
log.debug("Actual bytes {}", (char) b);
}
buffer.clear(); // Switch to write mode}}catch(IOException e) { e.printStackTrace(); }}}Copy the code
The contents of data.txt are:
1234567890abcd
Copy the code
The use of ByteBuffer
- Write data to Buffer, such as channel.read(Buffer);
- Call read mode
flip()
- To read data from buffer, call buffer.get();
- call
clear()
orcompact()
Switch to write mode, which explains the differences between the two methods.
The structure of the ByteBuffer
ByteBuffer has the following important properties:
- Capacity capacity
- Position (displacement)
- Limit Limit (equal to capacity)
When ByteBuffer is initialized:
In write mode, position is the write position and limit is the capacity. The following figure shows the state after 4 bytes have been written.
When filp() occurs, position switches to read position and limit switches to read limit.
After reading four bytes
After the clear action occurs, ByteBuffer is initialized:
The Compact () method compresses the unfinished section forward and switches to write mode, as shown in the following figure:
Common methods of ByteBuffer
- Allocate space ByteBuffer allocates space using the allocate method, which is also used for other buffers.
Such as:
ByteBuffer buf = ByteBuffer.allocate(10);
Copy the code
- Writes data to ByteBuffer
There are two methods:
- call
channel
theread
Methods; - Call buffer’s own PUT method;
Such as:
int readBytes = channel.read(buffer);
buf.put((byte)127);
Copy the code
- Read data from buffer
There are also two methods:
-
- call
channel
thewrite
Methods;
- call
-
- Call buffer’s get method;
Such as:
int writeBytes = channel.write(buf);
byte b = buf.get()
Copy the code
💡 note:
The get() method of buffer moves the position read pointer backwards if you want to read the data repeatedly:
- You can call the rewind() method to reset position to 0;
- A call to get(int I) gets the contents of index I, which does not move the read pointer back
Mark and reset for ByteBuffer
Mark is to make a mark when reading, even if the position changes, just call reset method can return to mark position
💡 Note: both rewind and Flip can clear the mark position. The former resets position to 0, and the latter switches read mode
Transposition of string and ByteBuffer
To convert ByteBuffer to a string, switch to read mode - flip() is the same as write mode */
ByteBuffer buffer1 = ByteBuffer.allocate(16);
buffer1.put("hello".getBytes());
debugAll(buffer1);
/** * 2. The string is converted to ByteBuffer */
ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("hello");
debugAll(buffer2);
/** * 3. The string is converted to ByteBuffer */
ByteBuffer buffer3 = ByteBuffer.wrap("hello".getBytes());
debugAll(buffer3);
/**
* ByteBuffer 转换为字符串
*/
String str3 = StandardCharsets.UTF_8.decode(buffer3).toString();
System.out.println(str3);
Copy the code
The Netty primer is over for now. If it is helpful, please click like attention.
Wechat search [code to meet you] to get more exciting content