[from getting started to giving up - Java] concurrent programming - NIO use

Keywords: Java network socket SpringBoot

Preface

Above [from getting started to giving up - SpringBoot] SpringBoot source code analysis - Request Process We learned that tomcat receives and returns requests based on NIO. There are many uses based on NIO in our daily work. We know that NIO can improve the concurrency of the system. In the next series, we will learn about NIO in depth. This article first gives a brief overview of its use.

NIO overview

NIO, or non blocking (New IO), refers to the new api provided in jdk1.4 and above.

The biggest difference between NIO and IO: IO processes data in the way of flow, while NIO processes data in the way of block; IO processes events in a blocking way, and NIO is non blocking

The core of NIO:

  • Channel
  • Buffer
  • Selector

NIO is mainly divided into standard I / O and network request

Standard I / O NIO

read

private static void readNio() {
    try {
        //1. Open file read stream
        FileInputStream fileInputStream = new FileInputStream("/Users/my/Desktop/123.txt");

        //2. Get fileChannel
        FileChannel channel = fileInputStream.getChannel();

        //3. Set the ByteBuffer size to accommodate capacity bytes at a time.
        int capacity = 9;
        ByteBuffer bf = ByteBuffer.allocate(capacity);

        //4. When read returns - 1, it means that the file has been read.
        int length = -1;
        while ((length = channel.read(bf)) != -1) {

            byte[] bytes = bf.array();
            System.out.println(new String(bytes, 0, length));

            //4. Set bf position to 0 for next reading.
            bf.clear();

        }
        channel.close();
        fileInputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Write in

private static void writeNio() {
    try {
        //1. Open file write stream
        FileOutputStream fileOutputStream = new FileOutputStream("/Users/my/Desktop/123.txt");

        //2. Get fileChannel
        FileChannel channel = fileOutputStream.getChannel();

        //3. Initialize byteBuffer
        String str = "The sada case happened greatly sdada34;sdds'";
        ByteBuffer bf = ByteBuffer.allocate(1024);

        //4. Set bf position to 0 for next reading.
        bf.clear();


        //5. Fill byte from the position of byteBuffer
        bf.put(str.getBytes());

        //6. Set bf position to 0 and limit to position to avoid too much writing.
        bf.flip();

        int length = 0;

        //7. If the position is less than the limit, the writing is not completed.
        while (bf.hasRemaining()) {
            //8. Write buffer contents to channel
            length = channel.write(bf);
            System.out.println(bf);
        }
        channel.close();
        fileOutputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Network NIO

Server side

package com.my.tools.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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class ServerSocket {
    private static ServerSocket serverSocket;

    private Selector selector;

    public static void main(String[] args) throws Exception {
        ServerSocket.getInstance().init(8001).listen();
    }

    public static ServerSocket getInstance() {
        if (serverSocket == null) {
            synchronized (ServerSocket.class) {
                if (serverSocket == null) {
                    serverSocket = new ServerSocket();
                }
            }
        }
        return serverSocket;
    }

    public ServerSocket init(int port) throws IOException {
        //Initialize channel
        ServerSocketChannel server = ServerSocketChannel.open();

        //Bind native 8001 port
        server.socket().bind(new InetSocketAddress(8001));

        //Set to non blocking mode
        server.configureBlocking(false);

        //Open selector Manager
        selector = Selector.open();

        //Register the selector to the server and set to handle only the accept event
        server.register(selector, SelectionKey.OP_ACCEPT);

        return this;
    }

    public void listen() throws Exception {
        System.out.println("server start");

        //Infinite loop continuous monitoring
        while (true) {
            //Will block until registered events are heard
            selector.select();

            //Get wakeup events
            Iterator<SelectionKey> selectorKeys = selector.selectedKeys().iterator();

            while (selectorKeys.hasNext()) {
                SelectionKey key = selectorKeys.next();

                //Delete the removed SelectionKey to prevent duplicate processing
                selectorKeys.remove();

                if (key.isAcceptable()) {

                    //Get the socket of the server
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();

                    //Get the received client socket
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);

                    //Write message to client
                    socketChannel.write(ByteBuffer.wrap(new String("hello, this is server").getBytes()));

                    //Register to listen to the read event
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("accept");
                } else if (key.isReadable()) {
                    //Use selector to get channel
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    socketChannel.configureBlocking(false);

                    ByteBuffer buffer = ByteBuffer.allocate(1024);

                    //Read news
                    int length = socketChannel.read(buffer);

                    String string = new String(buffer.array(), 0 , length);

                    System.out.println("read:" + socketChannel + string);

                    //Writing news
                    socketChannel.write(ByteBuffer.wrap(("server " + System.currentTimeMillis()).getBytes()));
                    Thread.sleep(10000);
                }
            }
        }
    }

}

Client

package com.my.tools.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;

public class ClientSocket {
    public static ClientSocket clientSocket;

    private static Selector selector;

    public static void main(String[] args) throws Exception {
        ClientSocket.getInstance().init("localhost", 8001).listen();
    }

    public static ClientSocket getInstance() {
        if (clientSocket == null) {
            synchronized (ClientSocket.class) {
                if (clientSocket == null) {
                    clientSocket = new ClientSocket();
                }
            }
        }

        return clientSocket;
    }

    public ClientSocket init(String ip, int port) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress(ip, port));
        socketChannel.configureBlocking(false);

        selector = Selector.open();
        socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);

        return this;
    }

    public void listen() throws Exception {
        System.out.println("client start");

        while (true) {
            selector.select();

            Iterator<SelectionKey> selectionKeys = selector.selectedKeys().iterator();

            while (selectionKeys.hasNext()) {
                SelectionKey selectionKey = selectionKeys.next();
                selectionKeys.remove();

                if (selectionKey.isConnectable()) {
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    socketChannel.configureBlocking(false);

                    ByteBuffer buffer = ByteBuffer.wrap(new String("hello, this is client").getBytes());
                    socketChannel.write(buffer);

                    socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("client write");
                } else if (selectionKey.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    socketChannel.configureBlocking(false);

                    ByteBuffer buffer = ByteBuffer.allocate(1024);

                    int length = socketChannel.read(buffer);

                    System.out.println("client read: " + socketChannel + new String(buffer.array(), 0, length));

                    socketChannel.write(ByteBuffer.wrap(("client " + System.currentTimeMillis()).getBytes()));

                    Thread.sleep(10000);
                }
            }

        }
    }
}

summary

The above example shows the simplest file NIO and network NIO usage. Next, we will analyze the source code of each method in depth and tune the performance.

For more articles, see: https://nc2era.com

Posted by Scrank.com on Fri, 01 Nov 2019 06:22:13 -0700