美文网首页
网络编程-NIO 理论部分

网络编程-NIO 理论部分

作者: 白璞1024 | 来源:发表于2020-02-16 12:07 被阅读0次

NIO- no_block IO 或者叫NewIO JAVA 1.4引入的

1 、NIO和BIO的区别

1.1、面向流和面向缓存

  • IO是面向流的,没有缓存去,所以如果需要前后移动从流中读取的数据,需要先将他缓存到一个缓存区。
  • NIO是面向缓存区

1.2、阻塞与非阻塞

  • java 的IO是阻塞模式的,当一个线程调用read()或者是write的时候,线程会被阻塞,
  • NIO非阻塞模式,是一个线程从某个通道发送请求读取数据,但是仅仅能得到目前可用的数据。如果目前没有可用的数据的时候,就什么都不会获取,而不是保持线性阻塞,没有获取到想要的信息的时候可以干其他的事情。所以一个单独的线程可以管理多个输入和输出的通道。

1.3、Select

  • NIO允许一个单独的线程来监视多个输入通道。可以注册多个通道使用一个选择器,然后使用一个单独的线程来选择通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

2、selector

selector选择器,轮训代理器,事件订阅器,channel容器管理器

应用程序将select对象注册需要它关注的Channel,以及具体的某一个Channel会对哪些IO事件感兴趣,Selector中也会维护一个已经注册的Channel的容器。

3、Channels

通道,被建立的一个应用程序和操作系统交互事件,传递内容的渠道,注意是连接到操作系统的 程序可以通过通道读取数据,也可以通过通道向操作系统写数据,而且可以同时进行读写。

  • 所有被select注册的通道,只能是继承了selectableChanne l类的子类
  • ServerSocketChannel应用服务器程序的兼听监听通道。只有通过这个通道,程序才能向操组系统注册支持’多路复用IO的端口监听。同时支持UDP,TCP
  • SocketChannel TCPSocket套接字的监听通道,一个Socekt对应了一个客户端的IP,端口到服务器IP端口的通信连接

通道中的数据总是要先读到一个Buffer或者,总是要从一个Buffer中写入

4、SelectionKey

select对象注册感兴趣的事件的时候,JAVA NIO共定义了四种 OP_READ、OP_WRITE、OP_CONNECT、 OP_ACCEPT

  • 服务器启动ServerSocketChannel关注OP_ACCEPT事件
  • 客户端启动SocketChannel连接服务器,关注OP_CONNECT事件
  • 服务器接受连接,启动一个服务器的SocketChannel,这个SocketChannel可以关注OP_READ OP_WRITE事件,一般连接后会直接关注OP_READ事件
  • 客户端这边的客户端SOCKETCHANNEL发现连接建立之后,可以关注OP_READ OP_WRITE事件,一般需要客户端发送数据了才会关注OP_READ事件

四、Buffer

用来和NIO通道进行交互,数据是从通道读入缓存区,缓存去写入到通道中的。以写为例:应用程序都是将数据写入缓存,在通过通道把数据发出去,读也是一样的。缓存本质上就是一个可以写入数据,然后可以读取数据的内存。这块内存被包装成NIO Buffer的对象,提供了一组方法,用来方便的访问这块内存。

1、重要属性

  1. capacity

内存卡,Buffer又一个固定的大小,就是capacity,一旦满了,需要清空(读数据,清除数据) 才能继续往里写数据。

  1. position

    当你写数据到Buffer中的时候,position表示当前的位置,初始position值是0.当一个byte, long,等数据写到Buffer后,position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity-1。读取数据的时候,也是也是从一个特定的位置开始读,Buffer写模式换成读模式的时候,position会重置成0档从Buffer的postion处读取数据的时候,position向前移动到下一个可读到位置。

  2. limit

    写模式下,Buffer的limit表示你最多能往Buffer里写多少的数据。写模式下,limit等于Buffer的capacity

    读模式下,Buffer到读模式的时候,limit表示你最多能读多少数据。切换Buffer到读模式的时候,limit会被设置成写模式的下的position值。你能读到之前写入的所有的数据。

2、Buffer的分配

想要活的一个Buffer对象首先要进行分配,每一个Buffer类都有allocate方法,可以在堆上分配,也可以直接内存上分配。

ByteBuffer buf = ByteByffer.allocate(48);//分配48字节的
CharBuffer buf = CharBuffer.allocate(1024);

把一个byte数组或者是byte数组的一部分包装成ByteBuffer

ByteBuffer wrap(byte[] array)
ByteBuffer wrap(butep[] array,int office,int length); 

HeapByteBufferDirectByteBuffer原理上,前者可以看出分配的buffer是在heap区域的,其实真正的flush到远程的时候,会先复制到直接内存,再做下一步操作。

NIO框架下,很多框架会采用DirectByteBuffer来操作,这样内存不再是heap上,而是操作在系统的C heap上,经过性能测试,可以得到非常快的网络交互。大量的网络交互下,一般速度会比HeapByteBuffer快速好几倍。

直接内存(Di re c t M e me o r y)并不是虚拟机运行时候数据区的一部分,也不是java虚拟机规范中定义的内存区域。这部分内存频繁的被使用,也可以导致OurOfMemoryError出现。NIO可以使用Native函数库直接分配对外内存,然后通过一个存储在java堆里边的DirectByteBuffer对象作为这个内存的应用进行处理

>1 堆外内存优缺点

相比较堆内内存有几个优势:

  1. 减少了垃圾回收的工作,因为垃圾回收会暂停其他的工作。
  2. 加快了复制的速度。省略了堆内flush到远程的时候,先复制到直接内存的过程;

不好的一面

  1. 难以控制,如果内存泄露,很难排查
  2. 不适合存储很复杂的对象,一般简单的对象或者是扁平化的比较合适。

>2 直接内存(堆外内存)与堆内存的比较

​ 直接内存申请空间耗费更多的性能。频繁处理的时候这一点很明显

​ 直接内存IO速度性能优于普通内存。多次读写操作的情况下,差异明显

3、Buffer的读写

1. 向Buffer中写数据

两种方式:

  • 读取Channel写到Buffer

    int bytesRead = inChannel.read(buf);//read into buffer
    
  • 通过Buffer的put()方法到Buffer

    buf.put(127);
    flip()方法:
    flip方法将Buffer从写模式切换到读模式,调用flip会将position改为0并将limit,设置成之前position的值。

2. 从Buffer中读取数据

  • 从Buffer读取数据写入到Channel

  • 使用get方法从Buffer中读取数据。

    int bytesWritten = inChannel.write(buf);//从Buffer读取数据到Channel
    bute aByte =buf.get();//从Buffer读取数据到Channel
    

使用Buffer读写数据常见步骤

  1. 写入数据到Buffer
  2. 调用flip()方法
  3. Buffer中读取数据
  4. 调用clear()方法或者 compact()方法,清除掉缓存中的数据。
  • clear()方法:position将被设回0 limit被设置成capacity的值,换句话说Buffer被清空了,Buffer中的数据并未清除。如果Buffer中又一些未读的数据,调用clear()方法,数据将被遗忘,以为不再有任何标记会告诉你哪些数据被读过,哪些还没有。

    如果Buffer中仍然有未读的数据,且后续还需要这些数据,但是此时想要先写些数据,那么使用conpact方法。

  • compact()方法将所有未读的数据拷贝到Buffer起始处,,然后将position设置到最后一个未读元素正后面,limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好些数据了,但是不会覆盖未读的数据。

  • equals()与compareTo()方法:比较两个Buffer

  • equals满足下列条件是,表示两个Buffer相等:

    • 有相同的类型(byte char int)
    • Buffer中剩余的byte,char等的个数
    • Buffer中所有剩余的byte,char等都相同。
  • compareTo()方法:

    compareTo方法比较两个Buffer的剩余元素,如果满足下列条件,认为一个Buffer小于另一个Buffer

    1. 第一个不相等的元素小于另一个Buffer中对应的元素。
    2. 所有元素都相等,但第一个Buffer比另一个先耗尽,第一个Buffer的元素个数比另一个少。

相关文章

  • 网络编程-NIO 理论部分

    NIO- no_block IO 或者叫NewIO JAVA 1.4引入的 1 、NIO和BIO的区别 1....

  • Java NIO

    书本 Netty权威指南netty实战O’Reilly的《Java nio》Unix网络编程 《unix网络编程》...

  • NIO网络编程

    1. NIO请求过程: 服务端:Selector 组件,循环检测注册事件就绪情况,(负责管理客户端与服务端建立的连...

  • Android 网络编程3 Java NIO

    Android网络编程 目录 1、Java NIO 的核心组件 Java NIO的核心组件包括:Channel(通...

  • BIO/NIO/AIO的几个思考

    BIO/NIO/AIO中的IO指的是什么?为什么网上一讲到BIO/NIO/AIO就是Socket编程、网络编程bl...

  • java Nio

    NIO编程 网络IO的介绍 nio的概述 通道、 缓冲区、 选择器 网络IO 讲网络IO前,我们先对同步、异步、阻...

  • Netty线程模型相关概念知识

    点击查看 官网[https://netty.io/] 点击查看NIO相关的知识 Java - NIO网络编程[ht...

  • 一文搞定NIO的三大组件

    提到NIO网络编程,就不得不提一下NIO中的三大组件: Buffer、Channel、Selector,JDK源码...

  • Java网络编程-NIO

    构造函数 首先放一个NIO的使用流程 1、创建ServerSocketChannel,配置为非阻塞模式 2、绑定监...

  • Java NIO网络编程

    OSI网络七层模型 低三层物料层:使用原始数据比特流能再物理介质上传输数据链路层: 通过校验、确认和反馈重发等手段...

网友评论

      本文标题:网络编程-NIO 理论部分

      本文链接:https://www.haomeiwen.com/subject/tqspfhtx.html