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 versionThe design of the

Basic concepts of selectorAnd what a selector does is it matchesA threadTo 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 trafficThe 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)

  1. Indirectly, through the input and output streams,
  2. 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

  1. Write data to Buffer, such as channel.read(Buffer);
  2. Call read modeflip()
  3. To read data from buffer, call buffer.get();
  4. callclear()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:

  • callchannelthereadMethods;
  • 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:

    1. callchannelthewriteMethods;
    1. 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