区块链技术博客
www.b2bchain.cn

NIO

这篇文章主要介绍了NIO的讲解,通过具体代码实例进行16235 讲解,并且分析了NIO的详细步骤与相关技巧,需要的朋友可以参考下https://www.b2bchain.cn/?p=16235

本文实例讲述了2、树莓派设置连接WiFi,开启VNC等等的讲解。分享给大家供大家参考文章查询地址https://www.b2bchain.cn/7039.html。具体如下:

NIO模型

1. 简介

Java NIO是从JDK1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓存区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。

两者的区别

BIO NIO
面向流(Stream Oriented) 面向缓冲区(Buffer Oriented)
阻塞IO(Blocking IO) 非阻塞IO(Non Blocking IO)
选择器(Selectors)

2. 工作流程

2.1 通道和缓冲区

通道表示打开到IO设备的连接,不存储数据。

缓冲区,对数据进行主要的处理

2.2 使用流程

**思想:**使用前,获取用于连接IO设备的通道以及用于容纳数据的缓冲区。

相较于传统BIO,NIO使用了双向通道,通道不用来传输任何数据,数据通过Buffer的移动来进行IO操作。

NIO

2.3 底层原理

NIO中引入了四个概念。

capacity缓冲区的容量,表示用来进行IO的最大数据量

limit第一个不应该进行写入或者读取的索引

position当前索引的位置,相当于一个读或者写的指针

mark和reset指向一个索引。可以通过remark`回到这个索引处

Buffer的底层是一个对应类型的数组

NIO

position<limit<capacity 其中的mark必须在0和limit之间

Java.nio包下提供了除了boolean类型的缓冲区

	ByteBuffer b ;      ShortBuffer s ;     IntBuffer i1 ;     LongBuffer l;     FloatBuffer floatBuffer ;     DoubleBuffer doubleBuffer ;     CharBuffer charBuffer ;

2.4 直接缓冲区和非直接缓冲区

直接缓冲区是直接创建在物理内存中的。通过allocate方法分配

非直接缓冲区是创建在堆中的。通过allocateDirect()方法分配

**非直接缓冲区的工作流程:**应用程序读取数据的时候,首先需要将数据加载到内核地址空间,然后再将数据复制到用户地址空间中,这样应用程序才可以读取。

NIO

**直接缓冲区工作流程:**应用程序读取数据的时候,直接在物理内存中读取,抛弃了复制的过程

NIO

2.5 通道的执行流程

将数据加载到内存中,然后IO接口创建一个通道,用来具体的数据读取

NIO

3. 简单的API

通道API

FileChannel  用于读取、写入、映射和操作文件的通道 DatagramChannel  通过UDP读写网络中的数据通道 SocketChannel   通过TCP读写网络中的数据 ServerSocketChannel 监听新进来的TCP连接,对于每一个进来的连接都会创建一个SocketChannel    

获取通道:

输入流的getChannel()方法 FileChannel的open方法 Files工具类中的newByteChannel

常见API用法

  • 字符的解码和加码,通过CharSet实现
  • 直接缓冲区的IO操作。
    • 通过BufferallocateDirect分配
    • 通过FileChannelopen方法创建
//打开文件,按照只读模式         try {             //指定了通道的模式,读取数据             FileChannel in = FileChannel.open(Paths.get("G:\BugReport.txt"), StandardOpenOption.READ);             //写数据,读数据,创建文件             FileChannel out = FileChannel.open(Paths.get("G:\BugReport3.txt"),                     StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);             //获取物理映射空间             MappedByteBuffer inMap = in.map(FileChannel.MapMode.READ_ONLY, 0, in.size());             MappedByteBuffer outMap = out.map(FileChannel.MapMode.READ_WRITE, 0, in.size());              //复制文件,先直接在物理空间中获取,然后再进行写入             byte[] bytes = new byte[inMap.limit()];             inMap.get(bytes);             outMap.put(bytes);              System.out.println();          } catch (IOException e) {             e.printStackTrace();         }

4. 网络非阻塞IO通信

对于传统的IO来说,都是阻塞的,即线程会一直等待数据,直到数据被读取或者写入。此时会造成大量的CPU资源浪费

而NIO中添加了一个选择器,他可以选择一个数据以及填充完成的通道发送给服务端执行。即当数据没有来之前,线程可以执行其他的事情.

非阻塞IO通信图

NIO

客户端:

public static void main(String[] args) throws IOException {         //1. 获取通道         SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 10001));          //2. 切换非阻塞模式         sChannel.configureBlocking(false);          //3. 分配指定大小的缓冲区         ByteBuffer buf = ByteBuffer.allocate(1024);          //4. 发送数据给服务端         Scanner scan = new Scanner(System.in);          while(scan.hasNext()){             String str = scan.next();             buf.put((new Date().toString() + "n" + str).getBytes());             buf.flip();             sChannel.write(buf);             buf.clear();         }          //5. 关闭通道         sChannel.close();     }

服务端:

public static void main(String[] args) throws IOException {         //1. 获取通道         ServerSocketChannel ssChannel = ServerSocketChannel.open();          //2. 切换非阻塞模式         ssChannel.configureBlocking(false);          //3. 绑定连接         ssChannel.bind(new InetSocketAddress(10001));          //4. 获取选择器         Selector selector = Selector.open();          //5. 将通道注册到选择器上, 并且指定“监听接收事件”         ssChannel.register(selector, SelectionKey.OP_ACCEPT);          //6. 轮询式的获取选择器上已经“准备就绪”的事件         while(selector.select() > 0){              //7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”             Iterator<SelectionKey> it = selector.selectedKeys().iterator();              while(it.hasNext()){                 //8. 获取准备“就绪”的是事件                 SelectionKey sk = it.next();                  //9. 判断具体是什么事件准备就绪                 if(sk.isAcceptable()){                     //10. 若“接收就绪”,获取客户端连接                     SocketChannel sChannel = ssChannel.accept();                      //11. 切换非阻塞模式                     sChannel.configureBlocking(false);                      //12. 将该通道注册到选择器上                     sChannel.register(selector, SelectionKey.OP_READ);                 }else if(sk.isReadable()){                     //13. 获取当前选择器上“读就绪”状态的通道                     SocketChannel sChannel = (SocketChannel) sk.channel();                      //14. 读取数据                     ByteBuffer buf = ByteBuffer.allocate(1024);                      int len = 0;                     while((len = sChannel.read(buf)) > 0 ){                         buf.flip();                         System.out.println(new String(buf.array(), 0, len));                         buf.clear();                     }                 }                  //15. 取消选择键 SelectionKey                 it.remove();             }         }       }

本文源码已经收录到本文开源项目MakerStack中,Github地址:https://github.com/StackInk/MakerStack

本文转自互联网,侵权联系删除NIO

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » NIO
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们