zoukankan      html  css  js  c++  java
  • 简述BIO/NIO/AIO前世今生

    如下程序是简单实现了一个极其简单的WEB服务器,用来监听某个端口,接受客户端输入输出信息。

    但这个程序有一个致命的问题就是连接会长时间阻塞

     于是BIO版本出现了,改成了  一个连接 一个线程来处理请求

     此时主程序会立即返回并等待下一个连接。但这个程序的问题是 每次一个连接 需要单独创建一个线程,服务器线程资源是优先的,而且1000个连接 有可能有效的读、写事件更少,所以NIO做法是一个

    归类问题:

    1. 每个请求都需要创建独立的线程,与对应的客户端进行数据处理。
    2. 当并发数大时,需要创建大量线程来处理连接,系统资源占用较大。
    3. 连接建立后,如果当前线程暂时没有数据可读,则当前线程会一直阻塞在 Read 操作上,造成线程资源浪费

    NIO

     

     下面附上一段NIO简易代码说明问题

    1)
    监听的事件有
    OP_ACCEPT: 接收就绪,ServerSocketChannel使用的
    OP_READ: 读取就绪,socketChannel使用
    OP_WRITE: 写入就绪,socketChannel使用
    OP_CONNECT: 连接就绪,socketChannel使用
    
    2)
    public static void main(String[] args) throws IOException {
            ServerSocketChannel ssc = ServerSocketChannel.open();//管道型ServerSocket
            ssc.socket().bind(new InetSocketAddress(Constant.HOST, Constant.PORT));
            ssc.configureBlocking(false);//设置非阻塞
            System.out.println(" NIO single server started, listening on :" + ssc.getLocalAddress());
    
            //Selector选择器可以监听多个Channel通道感兴趣的事情(read、write、accept(服务端接收)、connect,实现一个线程管理多个Channel,节省线程切换上下文的资源消耗。Selector只能管理非阻塞的通道,FileChannel是阻塞的,无法管理
    
            Selector selector = Selector.open();
            ssc.register(selector, SelectionKey.OP_ACCEPT);// 就绪事件【在建立好的管道上,注册关心的事件】
            while(true) {
                selector.select();
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> it = keys.iterator();
                while(it.hasNext()) {
                    SelectionKey key = it.next();
                    it.remove();//处理的事件,必须删除
                    handle(key);
                }
            }
        }
    
    /**
    * SocketChannel:从TCP网络中读取或者写入数据。
    * ServerSocketChannel:允许你监听来自TCP的连接,就像服务器一样。每一个连接都会有一个SocketChannel产生。
    */
        private static void handle(SelectionKey key) throws IOException {
            if(key.isAcceptable()) {
                    ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
    /**
    *

    如果此通道处于非阻塞模式,则此方法将立即返回NULL
    *否则它将无限期阻塞,直到有新连接可用为止
    *或发生I / O错误。

    @return 返回新创建的连接socketChannel

    或者返回NULL如果此通道处于非阻塞模式)
    *并且无法接受任何连接

    */

                    SocketChannel sc = ssc.accept();
                    sc.configureBlocking(false);//设置非阻塞
                    sc.register(key.selector(), SelectionKey.OP_READ );//[可读]在建立好的管道上,注册关心的事件 
            } else if (key.isReadable()) { //flip
                SocketChannel sc = null;
                    sc = (SocketChannel)key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(512);
                    buffer.clear();
                    int len = sc.read(buffer);
                    if(len != -1) {
                        System.out.println("[" +Thread.currentThread().getName()+"] recv :"+ new String(buffer.array(), 0, len));
                    }
                    ByteBuffer bufferToWrite = ByteBuffer.wrap("HelloClient".getBytes());
                    sc.write(bufferToWrite);
            }
        }
  • 相关阅读:
    leetcode 309. Best Time to Buy and Sell Stock with Cooldown
    leetcode 714. Best Time to Buy and Sell Stock with Transaction Fee
    leetcode 32. Longest Valid Parentheses
    leetcode 224. Basic Calculator
    leetcode 540. Single Element in a Sorted Array
    leetcode 109. Convert Sorted List to Binary Search Tree
    leetcode 3. Longest Substring Without Repeating Characters
    leetcode 84. Largest Rectangle in Histogram
    leetcode 338. Counting Bits
    git教程之回到过去,版本对比
  • 原文地址:https://www.cnblogs.com/zhangfengshi/p/14577492.html
Copyright © 2011-2022 走看看