IO知识详解

内核态和用户态

操作系统根据不同操作分为应用程序级别操作和系统级别的操作

应用程序运行在用户态,不能随便操作系统资源,保证系统资源的安全,如果用户程序需要操作系统资源,那么就去调用系统函数在内核态中由操作系统执行
在这里插入图片描述

IO

计算机角度的IO

我们常说的IO,就是计算机的输入输出,计算机是主体

计算机分为五个部分:运算器、控制器、存储器、输入设备、输出设备
在这里插入图片描述

操作系统角度的IO

真正的IO是在操作系统执行的。即应用程序的IO操作分为两种动作:

IO调用和IO执行。IO调用是由进程(应用程序的运行态)发起,IO执行是操作系统内核的工作

IO模型

阻塞IO

应用程序的发起IO调用,如果内核数据没有准备好,那应用程序进程就会一直阻塞等待,直到内核数据准备好,从内核拷贝到用户空间,才返回成功提示,此次IO操作,称为阻塞IO

阻塞IO的应用阻塞socket、javaBIO.阻塞IO的缺点:浪费性能,可以使用非阻塞式IO
在这里插入图片描述

非阻塞IO

应用程序的发起IO调用,如果内核数据没有准备好,就返回错误信息给用户进程,让它不需要等待,而是通过轮询的方式再来请求。这就是非阻塞式IO

非阻塞IO流程:

  • 应用程序向操作系统内核发起 recvfrom( )读取数据
  • 操作系统内核数据没准备好,立即返回EWOULDBLOCK 错误码
  • 应用程序进程轮询调用继续操作向系统内核发起 recvfrom( )读取数据
  • 操作系统内核数据准备好了,从内核缓冲区拷贝到用户空间。
  • 完成调用,返回提示

recvfrom()用来接收远程主机经socket 传来的数据,并把数据传到由参数
buf 指向的内存空间

非阻塞IO模型简称NIO,相对于阻塞IO,虽然提升了性能,但时它依然存在性能问题,即频繁的轮询,同样会消耗大量的CPU资源。可以考虑IO复用模型解决这个问题

IO多路复用

由于NIO无效的轮询会导致CPU资源消耗,所以我们可以等到内核数据准备好了,主动通知应用进程再去进行系统调用

IO复用模型核心思路:系统给我们提供了一类函数(select、poll、epoll),他们可以同时监视多个fd的操作,任何一个返回内核数据就绪,应用程序再发起recvfrom()系统调用

1.select():应用程序发起一次调用之后,就由select()函数负责监听,不需要轮询,当有数据准备好了,那么数据向用户态返回

select()可以同时监控多个 fd,在 select 函数监控的 fd中,只要有任何一个数据状态准备就绪了,select 函数就会返回可读状态,这时应用进程再发起 recvfrom( )请求去读取数据。
在这里插入图片描述

优点:不用轮询

缺点:监听连接数量有限制,最大监听1024.不能找到直接就绪的,需要对整个集合进行遍历,直到找到就绪的为止

2.poll( ) : 与select相同, 没有监听连接数量限制, 但同样需要遍历

3.epoll(): 给每一个fd绑定一个回调函数,当数据准备就绪后触发回调函数处理。
在这里插入图片描述

select、poll、epoll 的区别
在这里插入图片描述

信号驱动 IO 模型 :用户态向内核态发送一个信号,当内核态数据准备好了之后,内核态向用户态发送信息,用户态发起请求获取数据.

在这里插入图片描述

不管是 BIO,还是 NIO,还是信号驱动,在数据从内核复制到应用缓冲的时候,都是阻塞的。

异步 IO(AIO asynchronous IO)

AIO 是真正的非阻塞IO , 用户进程只需要发起一次调用,在内核态就会一次性直接将数据封装好,然后返回。

应用进程发出系统调用后,是立即返回的,但是立即返回的不是处理结果,而是表示提交成功类似的意思。等内核数据准备好,将数据拷贝到用户进程缓冲区,发送信号通知用户进程 IO 操作执行完毕。

在这里插入图片描述

阻塞、非阻塞、同步、异步 IO 划分:
在这里插入图片描述

同步阻塞(blocking-IO)简称 BIO
同步非阻塞(non-blocking-IO)简称 NIO
异步非阻塞(asynchronous-non-blocking-IO)简称 AIO

JavaNIO

JavaNIO是一个新的IO API,可以代替 Java IO API,NIO是支持缓冲区的、基于通道的IO操作。它可以以更高效的方式来进行文件的读写操作

阻塞IO(BIO)

在进行同步I/O操作时,读取、写入数据时,代码会阻塞直至数据准备就绪或能够写入时。

传统的 Server/Client 模式就是阻塞IO,为了解决阻塞IO,服务器和每个客户端请求建立一个线程,由该线程单独负责客户端的请求。但这样会导致线程数量激增,增加服务器的开销

非阻塞IO(NIO)

NIO中非阻塞I/O调用不会被阻塞,核心是注册特定的I/O事件

在发生特定事件时,系统再通知,NIO中实现非阻塞I/O的核心对象就是Selector

Selector就是注册各种I/O事件的地方
在这里插入图片描述

非阻塞指的是IO事件本身不阻塞,但是获取IO事件的select()方法是需要阻塞等待的

区别:BIO阻塞在IO操作上,NIO阻塞在事件获取上,没有事件就没有IO,从高层次上看IO不阻塞

NIO

Java NIO的核心组成成分

虽然Java NIO有很多类和组件,但核心就是 Channer、Buffer、Selector。

Channer(通道)

Channer 是一个对象,可以通过它读取、写入数据。所有数据通过Buffer对象处理,不会将数据直接写入通道,而是将数据写入缓冲区,再由缓冲区写入通道。读取数据同样如此。

主要实现:

FileChannel:从文件中读取数据

DatagramChannel:通过UDP读写网络中的数据

SocketChannel:通过TCP读写网络中的数据

ServerSocketChannel:j监听新进来的TCP连接
在这里插入图片描述

常用方法:

流对象.getChannel() 通过流对象获取管道

read(byteBuffer); 将数据导入缓存数据

write(byteBuffer);将数据从缓存数组写出

Buffer(缓冲区)

Buffer用于和Channel进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中

缓冲区本质是一块可以写入和读取数据的内存。

实现:ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer

对数据的读取/写入需要使用buffer,buffer本质是一个数组

常用方法: ByteBuffer.allocate(1024);创建字节数组

byteBuffer.clear();清除缓存,写操作前使用

byteBuffer.filp();翻转缓存区,读操作前使用

FileInputStream in = new FileInputStream("E:/source.txt");
        FileOutputStream out = new FileOutputStream("E:/dest.txt");
        FileChannel  inchannel =  in.getChannel();
        FileChannel  outchannel =  out.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
          while(inchannel.read(byteBuffer)!=-1){
              byteBuffer.flip();
              outchannel.write(byteBuffer);
              byteBuffer.clear();
          }
Selector(选择器)

选择器可以监听多个通道,一旦某个通道有事件(读,写,连接)发生,都会被选择器捕捉.

一个选择器可以监听多个通道,是非阻塞的,通过一个线程,就可以处理多个通道任务.

在这里插入图片描述

NIO 案例:

List<SocketChannel> list = new ArrayList<>();
        ServerSocketChannel serverSogketChannel = ServerSocketChannel.open();//创建服务器
        serverSogketChannel.bind(new InetSocketAddress(9999), 1024);
        serverSogketChannel.configureBlocking(false);//设置非阻塞

        //注册选择器
        Selector selector = Selector.open();//创建选择器
        serverSogketChannel.register(selector, SelectionKey.OP_ACCEPT);//向selector注册管道
        System.out.println("启动服务器");
        for (; ; ) {
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();//返回所有选择器接收到的操作
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                if (selectionKey.isAcceptable()) {//连接
                    ServerSocketChannel serverSockChannel = (ServerSocketChannel) selectionKey.channel();
                    SocketChannel acceptSocketChannel = serverSockChannel.accept();
                    System.out.println(acceptSocketChannel.getRemoteAddress());
                    acceptSocketChannel.configureBlocking(false);
                    acceptSocketChannel.register(selector, SelectionKey.OP_WRITE);
                }
                if (selectionKey.isWritable()) {//写
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    String resp = "响应";
                    try {
                        Thread.sleep(500);
                        socketChannel.write(ByteBuffer.wrap(resp.getBytes()));
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }
                if(selectionKey.isReadable()){//读
                    SocketChannel channel = (SocketChannel)selectionKey.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int length = channel.read(buffer);
                    String msg = "server receive msg:" + new String(buffer.array(), 0, length);
                    System.out.println(msg);
                }
                iterator.remove();
            }
        }
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序J

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值