1 Basic introduction

You can use a thread , Handle multiple client connections , Will be used to NIO Of Selector( Selectors ). Selector It can detect whether there are events on multiple registered server channels , If something happens , Then we get the events and deal with them accordingly . In this way, you can manage multiple channels with only one single thread , That is to manage multiple connections and requests .

image.png

In this case without a selector , Each connection corresponds to a processing thread . But connections don't send messages right away , So there will be a waste of resources

image.png

Only when there is a real read-write event on the channel , To read and write , It greatly reduces the system overhead , And you don't have to create a thread for each connection , No need to maintain multiple threads , It avoids the overhead caused by context switching among multiple threads

2 Commonly used API Introduce

Selector Class is an abstract class

image.png


Common methods :

Selector.open() : // Get a selector object

selector.select() : // Blocking Monitor all registered channels , When there is a corresponding event operation , Will SelectionKey Put inside the collection and return the number of events

selector.select(1000): // Blocking 1000 millisecond , Monitor all registered channels , When there is a corresponding event operation , Will SelectionKey Put it inside the collection and return

selector.selectedKeys() : // Return to being SelectionKey Set

SelectionKey

image.png


Common methods

SelectionKey.isAcceptable(): Whether it is a connection continuation event

SelectionKey.isConnectable(): Whether it is a connection ready event

SelectionKey.isReadable(): Whether it is a read ready event

SelectionKey.isWritable(): Whether it is a write ready event

SelectionKey As defined in 4 Events :

SelectionKey.OP_ACCEPT —— Receive connection continue event , Indicates that the server is listening to the client connection , The server can receive this connection

SelectionKey.OP_CONNECT —— Connection ready Events , Indicates that the connection between the client and the server has been established successfully

SelectionKey.OP_READ —— Read ready event , Indicates that the channel already has readable data , It's ready to read ( The channel currently has data , It's ready to read )

SelectionKey.OP_WRITE —— Write ready event , Indicates that data can be written to the channel ( Channels are currently available for write operations )

3 Selector code

Server implementation steps :

1. Open a server channel

2. Bind the corresponding port number

3. The channel is blocked by default , Need to be set to non blocking

4. Create selector

5. Register the server channel to the selector , And specify that the registered listening event is OP_ACCEPT

6. Check the selector for events

7. Get event collection

8. Determine whether the event is a client connection event SelectionKey.isAcceptable()

9. Get the client channel , And register the channel to the selector , And specify the listening event as OP_READ

10. Determine whether it is a client read ready event SelectionKey.isReadable()

11. Get the client channel , Read data to buffer

12. Write data back to the client

13. Delete the corresponding event from the collection , Because to prevent secondary treatment .

Code implementation :


package com.lagou.selector;

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.nio.charset.StandardCharsets;

import java.util.Iterator;

import java.util.Set;

/**

* Server side - Selectors

*/

public class NIOSelectorServer {

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

InterruptedException {

    //1. Open a server channel

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

    //2. Bind the corresponding port number

    serverSocketChannel.bind(new InetSocketAddress(9999));

    //3. The channel is blocked by default , Need to be set to non blocking

    serverSocketChannel.configureBlocking(false);

    //4. Create selector

    Selector selector = Selector.open();

    //5. Register the server channel to the selector , And specify that the registered listening event is OP_ACCEPT

    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

    System.out.println(" Server started successfully ...");

    while (true) {

      //6. Check the selector for events

      int select = selector.select(2000);

      if (select == 0) {

        continue;

     }

      //7. Get event collection

      Set<SelectionKey> selectionKeys = selector.selectedKeys();

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

      while (iterator.hasNext()) {

        //8. Determine whether the event is a client connection event SelectionKey.isAcceptable()

        SelectionKey key = iterator.next();

        //9. Get the client channel , And register the channel to the selector , And specify the listening event as OP_READ

        if (key.isAcceptable()) {

          SocketChannel socketChannel = serverSocketChannel.accept();

          System.out.println(" Client connected ......" + socketChannel);

          // The channel must be set to non blocking , because selector You need to poll to listen for events on each channel

          socketChannel.configureBlocking(false);

          // And specify the listening event as OP_READ

          socketChannel.register(selector, SelectionKey.OP_READ);

       }

        //10. Determine whether it is a client read ready event SelectionKey.isReadable()

        if (key.isReadable()) {

          //11. Get the client channel , Read data to buffer

          SocketChannel socketChannel = (SocketChannel) key.channel();

          ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

          int read = socketChannel.read(byteBuffer);

          if (read > 0) {

 System.out.println(" Client message :" +

                new String(byteBuffer.array(), 0, read,

StandardCharsets.UTF_8));

            //12. Write data back to the client

            socketChannel.write(ByteBuffer.wrap(" no

money ".getBytes(StandardCharsets.UTF_8)));

            socketChannel.close();

         }

       }

        //13. Delete the corresponding event from the collection , Because to prevent secondary treatment .

        iterator.remove();

     }

   }

 }

}

end ...