• 简述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);
            }
        }
  • 相关阅读:
    在Visual Studio中怎样快速添加代码段
    18个不常见的C#关键字,您使用过几个?
    C# 非常好用的组元Tuple
    C# List根据另一个List集合或数组排序
    Expression 核心操作符、表达式、操作方法
    如何避免频繁创建临时对象
    C# 23种设计模式
    C# 23种设计模式
    Api Cloud官方日期类型转换
    sql server 保留小数(续A)
  • 原文地址:https://www.cnblogs.com/StarbucksBoy/p/14577492.html
Copyright © 2020-2023  润新知