Netty principle detailed explanation series (1) --- Buffer&Chanel in NIO

1 Overview

In the BIO API, input and output are performed through two streams, InputStream and outPutStream. NIO uses a two-way communication channel instead of them. The channel (Channel) must rely on the buffer (Buffer) to achieve communication.

The pipeline comparison stream has more features such as non-blocking, off-heap memory mapping, and zero copy.

 

2. Buffer definition

The pipeline depends on the buffer, so let's first introduce the concept and use of the buffer.

An array is maintained inside the buffer to store data. The buffer does not support any data types stored, only some basic data types can be stored.

It has the functions of reading and writing and emptying. Without thread safety, you need to control thread safety by yourself.

Give everyone a benefit to receive a free Java architecture skill map. Note that it is free 

Free to receive the required +V to receive

3. Buffer internal structure

Take ByteBuffer as an example, it is a subclass of Buffer, used to store Byte type data, other buffers are similar, but the data types stored are different.

A byte array is maintained internally to store data.

The parent class Buffer has 4 important attributes:

  • capacity

    Indicates the size of the array

  • limit

    Limit the readable and writable range of Buffer, the default is equal to capacity

  • position

    The current reading and writing position, the default is 0, every time a bit is read or a bit is written, +1.

  • mark

    Make a mark for reset to set the position to this position. The default is -1

The position relationship of the four: mark <= position <= limit <= capacity

4. Buffer commonly used operations

4.1 allocate

Allocate the storage space of the buffer and initialize all the attributes. E.g:

Insert picture description here
The results obtained are as follows:
Insert picture description here

4.2 wrap

Pack a Buffer based on an array, position is 0, limit is the capacity value

The test code is as follows:

Insert picture description here
The buffer results are as follows:

Insert picture description here

4.3 put

Write to the buffer, the test code is as follows:

Insert picture description here

In the process of put, the position will be changed, that is to say, every time a number is written, the position will be +1. When the 7th write, the position will exceed the limit limit, and an exception BufferOverflowExeception will be thrown at this time
Insert picture description here

4.4 flip

Prepare for reading. After putting, execute flip to reset position and set it to 0.

The subsequent read operation starts from the position.

The test code is as follows:

Insert picture description here
The result of buffer after put 5 is executed is as follows:

Insert picture description here
Then execute flip, the results are as follows:
Insert picture description here
According to the results, you can see the role of flip, set position to 0

And the limit is set to the original position, the limit at this time limits the scope of reading.

4.5 get

Read the contents of the buffer, each time you read one, move one position after the position

The test code is as follows:

Insert picture description here

When the fifth is read, the contents of the buffer at this time are as follows: It
Insert picture description here
can be found that the position at this time has reached the limit of limit. If you read it again, it will report an error, read out of bounds exception BufferUnderflowException
Insert picture description here

4.6 mark

Set the mark bit and record the current position

The test code is as follows:

Insert picture description here

After executing the mark, set the mark property to position, that is, make a mark
Insert picture description here

4.7 reset

The function of reset is to set the value of position to mark, which is used to modify a piece of data in the buffer. Or read a piece of data in the buffer repeatedly.

The test code is as follows:
Insert picture description here

After executing reset, the buffer results are as follows

Insert picture description here

After recording the mark mark, two numbers were read and the two numbers were modified. After reset, position returns to the position recorded by mark. At this time, if you write again, you can modify the two numbers in the buffer. The result is as follows

Insert picture description here

4.8 clear

Reset the attributes of the buffer, but will not clear the data in the buffer

Set the position of position to 0, mark to -1. Limit is set to capacity

The test code is as follows:

Insert picture description here

After executing clear, the result of the buffer is as follows:

Insert picture description here

4.9 rewind

Prepare for re-reading. Set position to 0 and limit unchanged. mark is set to -1

The test code is as follows: After
Insert picture description here
executing rewind, the buffer results are as follows:
Insert picture description here

4.10 remaining

How many readable ranges are returned

Which is limit-position

The test code is as follows:
Insert picture description here
At this time, limit is equal to 5. After reading twice, the remaining method is executed, and the returned result is 3, indicating the remaining readable content

5. chanel

Pipes are used to connect files, network sockets, etc. It can perform read and write two I/O operations at the same time. It is called a bidirectional pipeline. It has two states of connection and closure. It is open when the pipeline is created. Once closed, it will report when the I/O operation is called. ClosedChannelException . It isOpen can be judged whether it is in the open state by the method of pipeline .

5.1 FileChannel file pipeline

The solid name suggests that it is used to manipulate files. In addition to normal operations, it also supports the following features:

  • Support to read and write to the specified area of ​​the file

  • Off-heap memory mapping, when large files are read and written, it can be directly mapped out of the JVM declared memory to improve read and write efficiency.

  • Zero-copy technology, through  transferFrom or transferTo directly transmitting data to a channel, greatly improves performance.

  • Lock the designated area of ​​the file to prevent other programmers from accessing it

Open FileChannel can only be opened through the stream at present, such as inputStream.getChannel() and outputStream.getChannel(), the pipeline opened through the input stream can only be accessed, and the outputStream can only be opened for writing. Otherwise, NonWritableChannelException and NonReadableChannelException will be thrown separately.

If you want the pipe to support both read and write, you must use the RandomAccessFile read and write mode.

The following test code is the basic use of file pipeline

				//1. 打开文件管道
        FileChannel channel = new RandomAccessFile(file_name,"rw").getChannel();

        ByteBuffer buffer=ByteBuffer.allocate(1024); // 声明1024个空间
        // 从文件中 读取数据并写入管道 再写入缓冲 channel.read(buffer); buffer.flip();//上面学的,写完之后,需要将position归0,为了后面的读取做准备 byte[] bytes= new byte[buffer.remaining()]; int i =0; while (buffer.hasRemaining()){ bytes[i++]= buffer.get(); } System.out.println(new String(bytes)); // 把缓冲区数据写入到管道 channel.write(ByteBuffer.wrap("森林大帅哥".getBytes())); channel.close(); 

 

5.2 DatagramChannel UDP socket pipe

UDP is a connectionless protocol, and DatagramChannel provides services for this protocol to receive messages from clients.

The basic usage of DatagramChannel is as follows:

public void test1() throws IOException { DatagramChannel channel=DatagramChannel.open(); // 绑定端口 channel.bind(new InetSocketAddress(8080)); ByteBuffer buffer=ByteBuffer.allocate(8192); while (true){ buffer.clear(); // 清空还原 channel.receive(buffer); // 阻塞 buffer.flip(); byte[] bytes=new byte[buffer.remaining()]; buffer.get(bytes); System.out.println(new String(bytes)); } } 

 

Use the command nc-uv 127.0.0.1 8080 to send udp to the specified ip port number

Insert picture description here
The idea console will output as follows:

Insert picture description here

5.3 TCP socket pipe

TCP is a connection protocol, and communication can only be done after a connection is established. This requires the following two pipelines:

  • **ServerSocketChannel: **Used to establish a connection with the client

  • **SocketChannel: **Used to read and write messages with the client

The test code is as follows:

@Test
public void test1() throws IOException { // 用于与客户端建立连接 ServerSocketChannel channel = ServerSocketChannel.open(); channel.bind(new InetSocketAddress(8080)); while (true) {//循环接收请求,分配子线程去执行请求 // 用于和客户端进行消息读写 SocketChannel socketChannel = channel.accept(); handle(socketChannel); } } public void handle(final SocketChannel socketChannel) throws IOException { // 2.通信 Thread thread = new Thread(new Runnable() { @Override public void run() { ByteBuffer buffer = ByteBuffer.allocate(8192); while (true) { try { buffer.clear(); socketChannel.read(buffer); // 从buffer 当中读出来 buffer.flip(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); String message = new String(bytes); System.out.println(message); // 写回去 buffer.rewind(); socketChannel.write(buffer); if (message.trim().equals("exit")) { break; } } catch (Exception e) { e.printStackTrace(); } } try { socketChannel.close(); } catch (IOException e) { e.printStackTrace(); } } }); thread.start(); } 

 

Can be tested by command TCP service telnet 127.0.0.1 8080

Insert picture description here

Guess you like

Origin blog.csdn.net/yuandengta/article/details/109183903