IO多路复用器

IO多路复用器,第1张

IO多路复用器 解决问题基础中断分类selectpollepoll java代码说明启动服务服务注册selectorselect事件处理

解决问题

同步:应用自己进行IO读写
异步:内核完成IO读写,应用没有访问IO,回调程序只是读取访问Buffer而已
阻塞:BLOCKING 程序堵塞等待IO
非阻塞:NONBLOCKING 程序不堵塞,如果没有IO,会返回-1
组合:同步阻塞、同步非阻塞、异步非阻塞

多路IO通过一个系统调用,可以获得其中IO状态,然后有程序对自己敢兴趣的IO状态进程 *** 作。

基础中断

分类 select

select函数需要遍历所有传入文件描述符的IO连接,只不过这个过程是由 *** 作系统内核完成的,只会触发一次系统调用。

select的IO中断响应只是把网卡数据通过DMA拷贝到select函数传入文件描述符的Buffer中。

传统的NIO这个遍历过程需要每次调用 *** 作系统内核完成查询IO状态,涉及到多次内核态用户态转换,系统执行效率底下。

Linux系统函数

poll

poll函数需要遍历所有传入文件描述符的IO连接,只不过这个过程是由 *** 作系统内核完成的,只会触发一次系统调用。

参考select

epoll

epoll系统函数,会在 *** 作中开辟一个系统空间,这个 *** 作空间是红黑树结构,内部维护了传入文件描述符集合,当有IO事件发生的时候,内核会将有IO状态发生的文件描述符拷贝到一个链表,应用程序只需要遍历这个链表就可以,无需遍历所有文件描述符,极大提升系统效率。

linux系统函数

java代码说明 启动服务服务注册selector
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(9090));
        serverSocketChannel.configureBlocking(false);
        //linux多路复用器 select poll epoll
        //打开Selector处理Channel
        Selector selector = Selector.open();
        //select,poll会在jvm里面开辟内存维护FD数组,epoll:elpoll_ctl添加到内核开辟的空间
        //把ServerSocketChannel注册到Selector上,并且selector监听accept连接事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
select事件处理
while(true){
            //它会阻塞等待需要处理的事件发生
            selector.select();
             //select,poll调用内核select(FDS),epoll调用epoll_wait
            //获取selector感知到的事件集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
		   //遍历SelectionKey,对事件进行处理
		    while(iterator.hasNext()){

          SelectionKey key = iterator.next();
        //如果是OP_ACCEPT连接事件。则进行连接获取和事件注册
        if(key.isAcceptable()){
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
            SocketChannel socketChannel = server.accept();
            socketChannel.configureBlocking(false);
            //注册读事件
            socketChannel.register(selector, SelectionKey.OP_READ);
        }else if(key.isReadable()){
            //如果是OP_READ读事件。则进行读取
            SocketChannel server = (SocketChannel) key.channel();
            ByteBuffer byteBuffer = ByteBuffer.allocate(32);
            int read = server.read(byteBuffer);

            if(read > 0){
                System.out.println("接收到消息:" + new String( byteBuffer.array() ));

            } else if(read == -1){//如果客户端断开连接,关闭socket
                iterator.remove();
                server.close();
            }

            //从事件集合中删除本次处理的key,防止下次重复处理
            iterator.remove();
        }
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/yw/926263.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存