Home  >  Article  >  Java  >  Analyze the usage and characteristics of Java NIO examples

Analyze the usage and characteristics of Java NIO examples

王林
王林forward
2023-05-06 22:25:06847browse

Analyze the usage and characteristics of Java NIO examples


1. Java mind map

Analyze the usage and characteristics of Java NIO examples

2. I/O model

The essence of the I/O model is what kind of channel is used to send and receive data, which largely determines the performance of program communication.
Java supports three network programming models: BIO, NIO, AIO

  • BIO: synchronization and blocking, the service implementation mode is one connection and one thread, that is, the client has one connection When making a request, the server needs to start a thread for processing.

  • NIO: Synchronous and non-blocking, the server implementation mode is a thread processing multiple request connections, that is, the requests sent by the client will be registered to the multiplexer and multiplexed The server polls the connection and processes it if there is an I/O request.

  • AIO: Asynchronous non-blocking, AIO introduces the concept of asynchronous channel, adopts Proactor mode, simplifies program writing, and only starts threads after valid requests. Its characteristic is that the operating system first Notify the server after completion.

3. BIO, NIO, AIO application scenarios

  • The BIO method is suitable for architectures with a relatively small and fixed number of connections. This method is suitable for The server resource requirements are relatively high, and concurrency is limited to applications. It was the only choice before JDK1.4, but the program is simple and easy to understand.

  • NIO method is suitable for architectures with a large number of connections and relatively short connections (light operations), such as chat servers, barrage systems, inter-server communications, etc. Programming is more complicated, and JDK1.4 starts to support it.

  • The AIO method is used in architectures with a large number of connections and relatively long connections (heavy operations), such as photo album servers, which fully call the OS to participate in concurrent operations. The programming is relatively complicated, and JDK7 begins to support it

4. Simple BIO programming process

  • The server starts a ServerSocket;

  • The client starts the Socket To communicate with the server, by default the server needs to establish a thread for each client to communicate with it;

  • After the client sends a request, it first consults the server whether there is a thread response, if not It will wait or be rejected;

  • If there is a response, the client thread will wait for the request to end before continuing execution;

5 , NIO core

NIO has three core parts: Selector (selector), Channel (channel), and Buffer (buffer).
NIO is buffer-oriented, or block-oriented programming. The data is read into a buffer that it will process later. It can be moved back and forth in the buffer when needed, which increases the flexibility in the processing process. Use It provides a non-blocking, highly scalable network.
HTTP2.0 uses multiplexing technology to allow the same connection to process multiple requests concurrently, and the number of concurrent requests is several orders of magnitude larger than HTTP1.1.
In short, NIO can handle multiple requests with one thread.

6. Comparison between BIO and NIO

  • BIO processes data in a stream, while NIO processes data in a block. Block I/O is more efficient than stream I/O. /O is much higher;

  • BIO is blocking, NIO is non-blocking;

  • BIO operates based on byte stream and character stream , and NIO operates based on Channel and Buffer. Data is always read from the channel to the buffer, or written from the buffer to the channel. Selector is used to monitor multiple channel events (such as connection requests, data arrival, etc.), so a single thread can monitor multiple client channels.

7. Schematic diagram of the three core principles of NIO

Analyze the usage and characteristics of Java NIO examples
Flow chart description:

  • Selector corresponding One thread, one thread corresponds to multiple channels (connections);

  • This picture reflects that there are three channels registered to the selector //program;

  • Each channel will correspond to a Buffer;

  • Which channel the program switches to is determined by events, and Event is an important concept;

  • Selector will switch on each channel according to different events;

  • Buffer is a memory block, and there is an array at the bottom;

  • Data is read and written through Buffer, which is the same as BIO. BIO is either an input stream or an output stream, which cannot be bidirectional. However, NIO's Buffer can be read or written, and the flip method is required to switch;

  • The channel is bidirectional and can return the status of the underlying operating system. For example, Linux, the underlying operating system channel is bidirectional;

8. Buffer

The buffer is essentially a memory block that can read and write data. It can be understood as a container object (including an array). This object Provides a set of methods to make working with memory blocks easier, and the buffer object has built-in mechanisms to track and record the buffer's state changes. Channel provides a channel for reading data from files and networks, but the data read or written must go through Buffer.
In NIO, Buffer is a top-level parent class, which is an abstract class.

1. List of commonly used Buffer subclasses

  • ByteBuffer, stores byte data in the buffer;

  • ShortBuffer, stores string data into the buffer;

  • CharBuffer, stores character data into the buffer;

  • IntBuffer, stores integers Data to the buffer;

  • LongBuffer, stores long integer data into the buffer;

  • DoubleBuffer, stores decimals into the buffer;

  • FloatBuffer, stores decimals in the buffer;

##2. Four major attributes of buffer

  • mark: mark

  • position: position, the index of the next element to be read or written, the value will be changed every time the buffer data is read or written, as the next Read and write preparation.

  • limit: Indicates the current end point of the buffer. Read and write operations cannot be performed on the buffer beyond the limit. And the limit can be modified

  • capacity: Capacity, that is, the maximum amount of data that can be accommodated; is set when the buffer is created and cannot be changed.

Analyze the usage and characteristics of Java NIO examples

3. Common buffer api

## introduced when JDK1.4

    ##public final int capacity( )//Returns the capacity of this buffer
  • public final int position( )//Returns the position of this buffer
  • public final Buffer position (int newPositio)//Set the position of this buffer
  • public final int limit( )//Return this buffer Limit
  • public final Buffer limit (int newLimit)//Set the limit of this buffer
  • public final Buffer mark()// Set the mark at the position of this buffer
  • public final Buffer reset( )//Reset the position of this buffer to the previously marked position
  • public final Buffer clear( )//Clear this buffer, that is, restore each mark to its initial state, but the data is not actually erased, and subsequent operations will overwrite it
  • ##public final Buffer flip( )//Reverse this buffer
  • public final Buffer rewind( )//Rewind this buffer
  • public final int remaining( )//Returns the number of elements between the current position and the limit
  • public final boolean hasRemaining( )//Informs whether there are elements between the current position and the limit
  • public abstract boolean isReadOnly( );//Inform whether this buffer is a read-only buffer
  • API introduced in JDK1.6

public abstract boolean hasArray();//Inform if this buffer has an accessible underlying implementation array
  • public abstract Object array();/ /Returns the underlying implementation array of this buffer
  • public abstract int arrayOffset();//Returns the offset of the first buffer element in the underlying implementation array of this buffer
  • public abstract boolean isDirect();//Inform whether this buffer is a direct buffer

9. Channel Analyze the usage and characteristics of Java NIO examples

1. Basic introduction

(1) NIO channel is similar to a stream

channel It can be read and written at the same time, while the stream can only read or write;
  • The channel can read and write data asynchronously
  • The channel can read and write data from Buffer to read data, you can also write data to the buffer
  • (2) The stream in BIO is one-way, for example, the FileInputStream object can only read data, while the stream in NIO Channel is bidirectional and can be read or written.
  • (3) Channel is an interface in NIO
(4) Commonly used Channel classes include: FileChannel, DatagramChannel, ServerSocketChannel and SocketChannel. ServerSocketChanne is similar to ServerSocket, and SocketChannel is similar to Socket.

(5) FileChannel is used for file data reading and writing, DatagramChannel is used for UDP data reading and writing, ServerSocketChannel and SocketChannel are used for TCP data reading and writing.


2. FileChannel

FileChannel is mainly used to perform IO operations on local files. Common methods are:

read , read data from the channel and put it in the buffer
  • write, write the data in the buffer to the channel
  • transferFrom, from Copy data from the target channel to the current channel
  • transferTo, copy data from the current channel to the target channel

3. Notes and details about Buffer and Channel

  • ByteBuffer supports typed put and get, put into What data type is, get should use the corresponding data type to retrieve, otherwise there may be a BufferUnderflowException exception.

  • You can convert a normal Buffer into a read-only Buffer.

  • NIO also provides MappedByteBuffer, which allows files to be modified directly in memory (memory outside the heap), and how to synchronize to files is completed by NIO.

  • NIO also supports reading and writing operations through multiple Buffers (i.e. Buffer arrays), namely Scattering and Gathering.

10. Selector(selector)

1. Basic introduction

  • Java’s NIO , using non-blocking IO mode. You can use one thread to handle multiple client connections, and you will use the Selector.

  • Selector can detect whether an event occurs on multiple registered channels. If an event occurs, it obtains the event and handles each event accordingly. In this way, only a single thread can be used to manage multiple channels, that is, to manage multiple connections and requests.

  • Reading and writing will only occur when there are actual read and write events on the connection/channel, which greatly reduces system overhead and eliminates the need to create a thread for each connection. No need to maintain multiple threads.

  • Avoids the overhead caused by context switching between multiple threads.

2. Selector related methods

  • ##open();//Get a selector object

  • select(long timeout);//Monitor all registered channels. When IO operations can be performed, add the corresponding SelectionKey to the internal collection and return it. The parameters are used to set the timeout.

  • selectedKeys();//Get all SelectionKeys from the internal collection.

3. Notes

ServerSocketChannel function in NIO is similar to ServerSocket, and SocketChannel function is similar to Socket.

11. Simple server-client communication through NIO

1. Server
package com.nezha.guor.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.*;import java.util.Iterator;public class NioServer {
    private Selector selector;
    private ServerSocketChannel serverSocketChannel;
    private static final int PORT = 8080;

    public NioServer() {
        try {
            //获得选择器
            selector = Selector.open();
            serverSocketChannel =  ServerSocketChannel.open();
            //绑定端口
            serverSocketChannel.socket().bind(new InetSocketAddress(PORT));
            //设置非阻塞模式
            serverSocketChannel.configureBlocking(false);
            //将该ServerSocketChannel 注册到selector
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        }catch (IOException e) {
            System.out.println("NioServer error:"+e.getMessage());
        }
    }

    public void listen() {

        System.out.println("监听线程启动: " + Thread.currentThread().getName());
        try {
            while (true) {
                int count = selector.select();
                if(count > 0) {
                    //遍历得到selectionKey集合
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();

                        if(key.isAcceptable()) {
                            SocketChannel sc = serverSocketChannel.accept();
                            sc.configureBlocking(false);
                            sc.register(selector, SelectionKey.OP_READ);
                            System.out.println(sc.getRemoteAddress() + " 上线 ");
                        }
                        //通道发送read事件,即通道是可读的状态
                        if(key.isReadable()) {
                            getDataFromChannel(key);
                        }
                        //当前的key 删除,防止重复处理
                        iterator.remove();
                    }
                } else {
                    System.out.println("等待中");
                }
            }
        }catch (Exception e) {
            System.out.println("listen error:"+e.getMessage());
        }
    }

    private void getDataFromChannel(SelectionKey key) {
        SocketChannel channel = null;
        try {
            channel = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            int count = channel.read(buffer);
            //根据count的值做处理
            if(count > 0) {
                String msg = new String(buffer.array());
                System.out.println("来自客户端: " + msg);

                //向其它的客户端转发消息(排除自己)
                sendInfoToOtherClients(msg, channel);
            }
        }catch (IOException e) {
            try {
                System.out.println(channel.getRemoteAddress() + " 离线了");
                //取消注册
                key.cancel();
            }catch (IOException ex) {
                System.out.println("getDataFromChannel error:"+ex.getMessage());
            }
        }finally {
            try {
                channel.close();
            }catch (IOException ex) {
                System.out.println("channel.close() error:"+ex.getMessage());
            }
        }
    }

    //转发消息给其它客户(通道)
    private void sendInfoToOtherClients(String msg, SocketChannel self ) throws  IOException{
        System.out.println("服务器转发消息中...");
        System.out.println("服务器转发数据给客户端线程: " + Thread.currentThread().getName());
        //遍历 所有注册到selector 上的 SocketChannel,并排除 self
        for(SelectionKey key: selector.keys()) {
            Channel targetChannel = key.channel();

            //排除自己
            if(targetChannel instanceof  SocketChannel && targetChannel != self) {
                SocketChannel dest = (SocketChannel)targetChannel;
                //将信息存储到buffer
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                //将buffer数据写入通道
                dest.write(buffer);
            }
        }
    }

    public static void main(String[] args) {
        //创建服务器对象
        NioServer nioServer = new NioServer();
        nioServer.listen();
    }}

2. Client
package com.nezha.guor.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Scanner;public class NioClient {
    private final int PORT = 8080; //服务器端口
    private Selector selector;
    private SocketChannel socketChannel;
    private String username;

    public NioClient() throws IOException {
        selector = Selector.open();
        socketChannel = socketChannel.open(new InetSocketAddress("127.0.0.1", PORT));
        //设置非阻塞
        socketChannel.configureBlocking(false);
        //将channel注册到selector
        socketChannel.register(selector, SelectionKey.OP_READ);
        username = socketChannel.getLocalAddress().toString().substring(1);
        System.out.println(username + " is ok...");
    }

    //向服务器发送消息
    public void sendInfo(String info) {
        info = username + " 说:" + info;
        try {
            socketChannel.write(ByteBuffer.wrap(info.getBytes()));
        }catch (IOException e) {
            System.out.println("sendInfo error:"+e.getMessage());
        }
    }

    //读取从服务器端回复的消息
    public void readInfo() {
        try {
            int readChannels = selector.select();
            if(readChannels > 0) {
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    if(key.isReadable()) {
                        //得到相关的通道
                        SocketChannel sc = (SocketChannel) key.channel();
                        //得到一个Buffer
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        //读取
                        sc.read(buffer);
                        //把读到的缓冲区的数据转成字符串
                        String msg = new String(buffer.array());
                        System.out.println(msg.trim());
                    }
                }
                iterator.remove(); //删除当前的selectionKey, 防止重复操作
            } else {
                System.out.println("没有可以用的通道...");
            }
        }catch (Exception e) {
            System.out.println("readInfo error:"+e.getMessage());
        }
    }

    public static void main(String[] args) throws Exception {
        NioClient nioClient = new NioClient();
        new Thread() {
            public void run() {
                while (true) {
                    nioClient.readInfo();
                    try {
                        Thread.currentThread().sleep(2000);
                    }catch (InterruptedException e) {
                        System.out.println("sleep error:"+e.getMessage());
                    }
                }
            }
        }.start();

        //发送数据给服务器端
        Scanner scanner = new Scanner(System.in);

        while (scanner.hasNextLine()) {
            nioClient.sendInfo(scanner.nextLine());
        }
    }}

3. Console output

Analyze the usage and characteristics of Java NIO examples
Analyze the usage and characteristics of Java NIO examples


The above is the detailed content of Analyze the usage and characteristics of Java NIO examples. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete