NIO/BIO from JAVA Network IO

Keywords: Java network

Series articles: Knowledge Context

Preface  

  • Java's IO, or Input/Output, is divided into IO devices and IO interfaces.
    • I often hear input and output streams, input and output bytes, input and output characters... Java interaction with the outside can be converted into streams, byte characters and then encapsulated as objects, thus facilitating programmer programming.
  • Java interaction with the network is network IO, Java interaction with disk is disk IO.
  • What is Java Network IO? read the data from the socket with the system call.

  1. Basic Java Network Programming

1,Socket

  • Two programs on the network exchange data through a two-way communication connection.
  • The two endpoints of this two-way communication link are called sockets and are often used to connect.
  • A socket must consist of an IP+port number port.
  • A socket is a programming interface that supports protocols such as TCP/IP.

2. Socket s in Java

  • Sockets in Java are mainly TCP/IP based.
  • Sockets (client) and serverSocket s (server) are provided in Java's java.net package.
  • How to use socket s in Java:
    1. Create socket
    2. Open input/output streams connected to socket s
    3. Read/write socket s by protocol
    4. Close socket    

3. IO in Java    

After the Socket is built, there is no problem with the network data transmission path, so how to read the data?

  • Packages available for reading JDK 1.0 - java.io
  • Java's I/O input/output system solves the following issues:
    • Various I/O sources and receivers to communicate with (file/console/network link...)
    • There are many different ways to communicate: sequential/random/buffer/binary/character, word, line...
    • Java's Stream masks the details of processing data in an I/O device.

  II. Historical Evolution of Java Network IO

It is not so much the IO history of Java as the network IO history of the operating system.

  • read is the method of the operating system, and java just calls this interface.

Take Linux for example:

Stage 1: Call read to read socket data, read if there is data, wait if there is no data.

Stage 2: Call read to read socket data, read if there is data, and return -1 if there is no data.

                  Erno is set to EAGAIN.

Stage 3: Listen for socket s and notify if there is data.

Phase 1   Java Network Programming

Stage 1: Call read to read socket data, read if there is data, wait if there is no data.

How do you design Java programs on this premise?

  • If a thread is blocked in read, only a new thread can be opened in order for the program to continue executing down.

1. Programming examples for code

  A) ServerSocket server-side channel construction pseudocode example

public class ServerSocketDemo {
    public static void main(String[] args) throws IOException {
        // Create a thread pool
        ExecutorService threadPool = Executors.newCachedThreadPool();
        // Create ServerSocket
        ServerSocket serverSocket = new ServerSocket(3000);
        // Dead loop (listening for serverSocket), waiting for client connection
        while (true) {
            Socket clientSocket = serverSocket.accept(); 
            // Create a thread to process communication data
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    //handler method is the method for processing data: see B below) IO processing data is a code example
                    handler(clientSocket); 
                }
            });
        }
    }
}

B) IO Processing Data as Code Example

private static void handler(Socket clientSocket) throws IOException {
        //Receive data, block when no data is readable
        int read = clientSocket.getInputStream().read(new byte[1024]);
        if (read != -1) {
            //Business Methods for Processing Data
        }
}

2. Malpractices

The read() operation is stuck (blocked). If a single thread is likely to get stuck, if multiple threads (as above) can solve the stuck problem, but what is the impact?

  • Each thread handles one network request, and 1000 concurrent requests open 1000 threads.
  • Each thread takes up a certain amount of memory as a thread stack, and each 1M, 1000 is 1G.
  • These 1000 threads are idle when there is no data.
  • If a thread pool is used, the number of concurrencies is limited.

3. Summary

This call reads socket data, reads if there is data, and waits if there is no data. Called BIO, blocking IO.

  Phase 2   Java Network Programming

Stage 2: Call read to read socket data, read if there is data, and return -1 if there is no data.

                  Erno is set to EAGAIN.

What changes have Java made to this? NIO model coming on!

  • NIO adds a Buffer.
    • Stream-oriented means that one or more bytes are read from the stream at a time until all bytes are read, and they are not cached anywhere.
    • NIO data is read into a buffer that it processes later and can move forward and backward in the buffer if needed. Increased processing flexibility.
    • At the bottom of the buffer is an array.

  • NIO adds a new two-way Channel.
    • A single thread can now manage multiple input and output channel s.
  • NIO adds a multiplexer (Selector).
    • Register Channel on Selector
    • Selector can listen to four states of Channel (Connect, Accept, Read, Write)
    • When a Channel's state is monitored, the Channel is operated on accordingly

What is the corresponding operating system?

  • The underlying NIO implementation in JDK1.4 is the linux kernel function select() or poll().
  • The bottom level of NIO in JDK1.5 is to optimize NIO based on event response mechanisms using linux's kernel function epoll().

The main implementation of I/O multiplexing underlying layer is the Linux kernel/function (select, poll, epoll)

Windows does not support epoll implementation, the bottom level of windows is based on winsock2 select function (open source)

 

 

1. How does NIO work? Client Code Sample

public class NioServer {

    public static void main(String[] args) throws IOException, InterruptedException {

        // Create NIO ServerSocketChannel
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(9000));
        // Set ServerSocketChannel as non-blocking
        serverSocket.configureBlocking(false);
        // Open Selector to process Channel, creating epoll
        Selector selector = Selector.open();
        // Register ServerSocketChannel with selector and selector is interested in client accept connection operations
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            // Block waiting for events to be processed to occur
            selector.select();
            // Get SelectionKey instances of all events registered in selector
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            // Traverse SelectionKey to process events
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // If OP_ACCEPT events, connection acquisition and event registration
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    // Only read events are registered here, and write events can be registered if data needs to be sent to the client
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    //Client Connection Successful
                // If OP_READ events, read and print
                } else if (key.isReadable()) {  
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(128);
                    int len = socketChannel.read(byteBuffer);
                    // If there is data
                    if (len > 0) {
                        //receive data
                        String data = new String(byteBuffer.array());
                        //Perform business logic for processing data
                    // Close Socket if client disconnects
                    } else if (len == -1) { 
                        //Client disconnects, closes socket
                        socketChannel.close();
                    }
                }
                //Remove the key of this process from the event collection to prevent the next select from repeating
                iterator.remove();
            }
        }
    }
}

  2. Summary

The entire NIO call process is

  • Java calls the operating system's kernel function to create a Socket and get the Socket's file descriptor.
  • Java then creates a Selector object that corresponds to the Epoll descriptor of the operating system and binds the events of the file descriptor of the acquired Socket connection to the Epoll file descriptor of the Selector.

Asynchronous notification of events

  • Implemented using one thread
  • Not much invalid traversal is required
  • Handling events to the operating system kernel (OS interrupt program implementation)
  • Greatly improved efficiency

 

Posted by skulk on Thu, 21 Oct 2021 10:55:38 -0700