NIO Selector execution process

1, What is Seletor?

The literal meaning of selector is not easy to understand. Seletor is a listener that can listen to events in the Channel. Channels can be registered in the seletor. When these registered channels have events, the seletor's select method will return these events to the thread for processing.

2, The difference between Seletor and multithreading

The above explanation is not easy to understand. We need to understand its purpose in combination with the design evolution of the server

Multithreaded version design

For the client socket requests in the network, if a thread is opened to process each request, the system memory consumption is high, the thread context switching cost is also high, and the pressure on the system will be very large.

Thread pool version design

Using thread pool optimizes the creation of threads, but in blocking mode, threads can only handle one socket connection, which is only suitable for short connection scenarios

selector version

The function of selector is to cooperate with a thread to manage multiple channels and obtain the events that occur on these channels. These channels work in non blocking mode and will not let the thread hang on a channel. It is suitable for scenarios with a large number of connections but low traffic

3, selector single thread processing multiple socket cases

Server code:

@Slf4j
public class ChannelDemo6 {
    public static void main(String[] args) {
        try (ServerSocketChannel channel = ServerSocketChannel.open()) {
            channel.bind(new InetSocketAddress(8080));
            System.out.println(channel);
            Selector selector = Selector.open();
            channel.configureBlocking(false);
            channel.register(selector, SelectionKey.OP_ACCEPT);

            while (true) {
                int count = selector.select();
                 log.debug("select count: {}", count);


                // Get all events
                Set<SelectionKey> keys = selector.selectedKeys();

                // Traverse all events and handle them one by one
                Iterator<SelectionKey> iter = keys.iterator();
                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                    // Judge the event type
                    if (key.isAcceptable()) {
                        ServerSocketChannel c = (ServerSocketChannel) key.channel();
                        // Must handle
                        SocketChannel sc = c.accept();
                        sc.configureBlocking(false);
                        sc.register(selector, SelectionKey.OP_READ);
                        log.debug("Connection established: {}", sc);
                    }
                    else if (key.isReadable()) {
                        SocketChannel sc = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(128);
                        int read = sc.read(buffer);
                        if(read == -1) {
                            key.cancel();
                            sc.close();
                        } else {
                            buffer.flip();
                            debugAll(buffer);
                        }
                    }
                    // After processing, the event must be removed
                    iter.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client code:

public class Client {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 8080)) {
            System.out.println(socket);
            socket.getOutputStream().write("world".getBytes());
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Method explanation:

  • ServerSocketChannel is used to create the Channel of the server, which is a bit like ServerSocket
  • channel.configureBlocking(false); Set the channel to non blocking, so that if there is no connection when accpet, it will return null
  • channel.register(selector, SelectionKey.OP_ACCEPT) registers the channel in the selector and listens for accept connection events
  • selector.select() will block and wait for the client to connect
  • selector.selectedKeys(), an event producer, will add events to this collection

4, selector event

  • Triggered when accept generates a connection
  • Start when the connect client establishes a connection
  • read generates a readable event when a client message is received
  • Writable events

Tags: Java NIO programming language

Posted by Fari on Tue, 02 Aug 2022 21:10:27 +0300