JAVA BIO, NIO, Reactor model summary

Traditional synchronous blocking I / O (BIO)

Write server used prior to NIO is synchronous blocking I / O (Blocking I / O). Here is a typical example of the server thread pool customer service side code, which in the case of a sharp rise in the number of connections, the server code will not help, because serverSocket.accept (), and the IO read (), write () methods are synchronous blocking, although by the thread pool, to avoid the frequent create a thread overhead, but the system is too dependent on the thread, a thread creation and destruction is very time-consuming. Furthermore great thread switching overhead, especially in system pressure would be unthinkable in the case of high concurrency.

BIO customer terminal server thread pool sample code

/**
 * BIO服务器
 * @author monkjavaer
 * @date 2019/7/17 13:55
 */
public class BioServer {
    public static final int PORT = 8888;
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(PORT);
            Socket socket = null;
            ThreadFactory namedThreadFactory = new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r);
                    t.setName("demo-pool-%d");
                    return t;
                }
            };
            //通过线程池,避免频繁创建线程开销
            ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

            //主线程死循环等待新连接到来
            while(!Thread.currentThread().isInterrupted()){
                socket = serverSocket.accept();
                singleThreadPool.execute(new BioServerHandler(socket));
            }
        } catch (IOException e) {
            //TODO异常处理
        } finally {
         //TODO关闭资源
        }
    }
}
/**
 * BIO服务器事件处理方法
 * @author monkjavaer
 * @date 2019/7/17 14:00
 */
public class BioServerHandler implements Runnable {
    private Socket socket;
    public BioServerHandler(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            byte[] input = new byte[1024];
            //服务器接收的数据
            socket.getInputStream().read(input);
            byte[] output = "服务器返回数据".getBytes();
            socket.getOutputStream().write(output);
       } catch (IOException e) {
            //TODO异常处理
        } finally {
         //TODO关闭资源
        }
    }
}
/**
 * 服务端
 * @author monkjavaer
 * @date 2019/7/17 15:06
 */
public class BioClient {
    public static final int PORT = 8888;
    public static final String IP = "127.0.0.1";
    public static void main(String[] args) {
        Socket socket = null;
        PrintWriter printWriter = null;
        try {
            socket = new Socket(IP,PORT);
            socket.setSoTimeout(5000);
            printWriter = new PrintWriter(socket.getOutputStream());
            printWriter.println("客户端发送数据");
            printWriter.flush();
        } catch (IOException e) {
            //TODO异常处理
        } finally {
         //TODO关闭资源
        }
    }
}

The NIO (non-blocking I / O)

NIO is non-blocking I / O (Non-blocking I / O)

NIO important component Review

  • Buffer (Buffer): Object Buffer is a fixed number of data container. Its role is a memory, or a staging area, where data can be stored and used after retrieval. ByteBuffer, IntBuffer, CharBuffer, LongBuffer, DoubleBuffer, FloatBuffer, ShortBuffer is its implementation class.
  • Channel (Channel): Channel byte buffer and for the passage of the entity on the other side (typically a file or socket) efficiently transfer data between. Channel is full duplex.
  • A selector (Selector): Selector multiplexer is NIO. Selector will continue to poll registered on it's channel Channel, find a ready state Channel (Channel channel occurs reading and writing events). Selector mechanism is based on the underlying operating system, different models, different versions distinction. On Linux depends on the epoll; there is no limit on the maximum handle, thus a do Selector polling thread can access the large number of client connections.

NIO server Sample Code

NIO server code step to achieve very much more complicated, it is recommended to use a mature framework NIO Netty and so on.

public class NioServer implements Runnable {
    private static Logger LOGGER = LoggerFactory.getLogger(NioServer.class);
    @Override
    public void run() {
        try {
            //1、打开ServerSocketChannel,监听客户端的链接
            ServerSocketChannel serverSocket = ServerSocketChannel.open();
            //2、绑定监听端口,设置backlog(默认50):请求传入连接队列的最大长度
            serverSocket.socket().bind(new InetSocketAddress(9011), 1024);
            //3、false,设置为非阻塞模式
            serverSocket.configureBlocking(false);
            //4、创建Selector,Selector是NIO的多路复用器,Selector会不断轮询注册在它上面的通道Channel,
            //找出就绪状态的Channel(Channel通道发生读、写事件)。
            Selector selector = Selector.open();
            //5、注册通道Channel到多路复用器Selector,并说明关注点SelectionKey.OP_ACCEPT,监听ACCEPT事件
            serverSocket.register(selector, SelectionKey.OP_ACCEPT);
            LOGGER.info("Listening on port {}" , 9011);

            //6、Selector轮询就绪的Channel
            while (true) {
                // 阻塞等待就绪的 Channel,这是关键点之一
                //selector1秒被唤醒
                int n = selector.select(1000);
                if (n == 0) {
                    continue;
                }
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> iter = selectedKeys.iterator();
                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                    if (key.isValid()) {

                        if (key.isAcceptable()) {
                            //SelectionKey可以获取就绪状态的Channel
                            ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                            //7、多路复用器Selector监听到有新的客户端连接,完成TCP三次握手建立连接。
                            SocketChannel clientSocketChannel = serverSocketChannel.accept();
                            //8、设置客户端SocketChannel为非阻塞模式
                            clientSocketChannel.configureBlocking(false);
                            //9、注册加入新的通道OP_READ
                            clientSocketChannel.register(selector, SelectionKey.OP_READ);
                        }

                        //读取客户端数据
                        //if(key.isReadable())等价于if((key.readyOps( ) & SelectionKey.OP_READ) != 0)
                        if (key.isReadable()) {
                            SocketChannel socketChannel = (SocketChannel) key.channel();
                            //创建buffer
                            ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                            int readPosition = socketChannel.read(readBuffer);
                            if (readPosition > 0) {
                                //flip()方法,Buffer从写模式切换到读模式,将limit设置为position,position设为0。
                                readBuffer.flip();
                                byte[] bytes = new byte[readBuffer.remaining()];
                                //从可读buffer中读取数据
                                readBuffer.get(bytes);
                                LOGGER.info("接收客户端发送消息:{}" , new String(bytes, StandardCharsets.UTF_8));

                                byte[] sendBytes = "server 收到".getBytes();
                                ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
                                writeBuffer.flip();
                                //put 向buffer添加元素
                                writeBuffer.put(sendBytes);
                                socketChannel.write(writeBuffer);
                            }

                            if (readPosition < 0) {
                                // Close channel on EOF, invalidates the key
                                key.cancel();
                                socketChannel.close();
                            }
                        }
                    }
                    iter.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread(new NioServer()).start();
    }
}
public class NioClient {
    private static Logger LOGGER = LoggerFactory.getLogger(NioClient.class);
    private static int PORT = 9011;
    private static String[] messages = {"这是服务器"};

    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(InetAddress.getLocalHost(), PORT));
            for (String msg : messages) {
                ByteBuffer myBuffer = ByteBuffer.allocate(1024);
                myBuffer.put(msg.getBytes());
                myBuffer.flip();
                socketChannel.write(myBuffer);
            }
            LOGGER.info("Closing Client connection...");
            socketChannel.close();
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
        }
    }

}

Reactor mode

First Reactor pattern is event-driven, concurrent with one or more input sources, there is a Service Handler, a plurality Request Handlers; the Service Handler will request (Event) multiplexed input corresponding to distribute synchronization Request Handler. It is a process for the concurrent service request, and the request is submitted to one or more service model designed event handlers.

Reactor mode modules

http://www.blogjava.net/DLevin/archive/2015/09/02/427045.html

Scalable IO in Java text and translation

http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf
https://www.cnblogs.com/luxiaoxun/archive/2015/03/11/4331110.html

Reactor An Object Behavioral Pattern for Demultiplexing and Dispatching Handles for Synchronous Events

http://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf

Guess you like

Origin www.cnblogs.com/monkjavaer/p/11209141.html