9-高并发-IO读写的底层原理-句柄配置修改-JAVA NIO三大组件

一、内核缓冲区:

  • IO读写对于往往都是指上层程序的IO操作。实际上不是物理设备级别的读写,反而是缓存的复制。
  • read和write都不负责数据在物理设备和内核缓冲区之间的交换。这项底层交换,由操作系统内核(Kernel)来完成。
  • 在应用程序中,无论是Socket的IO、还是文件IO操作,都属于上层应用的开发。

二、进程缓冲区:

  • 内核缓冲区是为了减少频繁的与设备之间物理交换。
  • 上层应用使用read系统调用时,仅仅把数据从内核缓冲区复制到上层应用的缓冲区(进程缓冲区)。
  • 上层应用使用write系统调用时,仅仅把数据从进程缓冲区复制到内核缓冲区。这样,底层操作由操作系统控制(如读写中断)用户程序无需关心。
  •                                      9-高并发-IO读写的底层原理-句柄配置修改-JAVA NIO三大组件_第1张图片

三、四种主要IO模型

  • 同步阻塞IO-Blocking IO
  • 9-高并发-IO读写的底层原理-句柄配置修改-JAVA NIO三大组件_第2张图片
  • 通步非阻塞IO-None Blocking IO
  • 9-高并发-IO读写的底层原理-句柄配置修改-JAVA NIO三大组件_第3张图片
  • 异步IO模型-Asynchronous IO
  • 9-高并发-IO读写的底层原理-句柄配置修改-JAVA NIO三大组件_第4张图片

四、合理配置

及时采用最先进的模型,还需要进行合理的配置,就是Linux操作系统中文件句柄数的限制。默认为1024,即一个进程最多可以接受1024个socket连接。

五、Java NIO通信

  • java NIO的三个核心组件:Channel、Buffer、Selector
  • OIO:面向流(字符/字节),按照流的方式顺序读取,不能随意改变指针。阻塞的。
  • NIO:面向缓冲区,可随意读取Buffer中任意位置数据。非阻塞。

5.1Buffer: 重要成员属性:

  • capacity(容量-个数数量)、
  • position(读写位置)、
  • limit(读写限制)。
  • mark(标记、临时存放position)

在写入模式下,position的值变化规则如下:

  1. 在刚进入到写模式时,position值为0,表示当前的写入位置为从头开始。
  2. 每当一个数据写到缓冲区之后,position会向后移动到下一个可写的位置。
  3. 初始的position值为0,最大可写值position为limit-1。当position值达到limit时,缓冲区就已经无空间可写了。

在读模式下,position的值变化规则如下:

  1. 当缓冲区刚开始进入到读模式时,position会被重置为0。
  2. 当从缓冲区读取时,也是从position位置开始读。读取数据后,position向前移动到下一个可读的位置。
  3. position最大的值为最大可读上限limit,当position达到limit时,表明缓冲区已经无数据可读。

flip翻转:

  1. 起点在哪里呢?当新建一个缓冲区时,缓冲区处于写入模式,这时是可以写数据的。
  2. 数据写入后,如果要从缓冲区读取数据,这就要进行模式的切换,可以使用(即调用)flip翻转方法,将缓冲区变成读取模式。
  3. 在这个flip翻转过程中,position会进行非常巨大的调整。
  4. 具体的规则是:position由原来的写入位置,变成新的可读位置,也就是0,表示可以从头开始读。flip翻转的另外一半工作,就是要调整limit属性。

5.2Buffer: 重要方法:

  • allocate()创建缓冲区
  • put()写入到缓冲区
  • flip()翻转:设置长度上限limit,设置position位置,清除mark
  • get()从缓冲区读取
  • rewind()倒带
  • mark()和reset():mark-将当前position保存。reset-将mark恢复到position
  • clear()清空缓冲区

 

9-高并发-IO读写的底层原理-句柄配置修改-JAVA NIO三大组件_第5张图片

5.3NIO Channel-通道类

通道的主要类型:FileChannel(文件)、SocketChannel(TCP连接)、ServerSocketChannel(监听)、DatagramChannel(UDP)

数据总是从通道读到缓冲区、或者从缓冲区写入到通道

5.4NIO Selector选择器

  • 选择器的使命是完成IO的多路复用。
  • 一般来说,一个单线程处理一个选择器,通过选择器,可以处理数百上千的通道。会大量减少线程之间上下文切换的开销。
  • 注册:通道注册选择器Channel.register(Selectorsel-选择器实例,int ops-要监控IO书事件类型)
  • 选择就绪事件:一个IO事件发生,如果在选择器中注册过,就会被选择器选中,并放入SelectionKey选择键集合中。
  • 选择器的使用流程:1.获取选择器实例2.将通道注册到选择器3.选出感兴趣的IO事件(选择器集合)
  • select方法:select()-阻塞调用,一直到至少一个通道发生IO事件。
  • select方法:select(Long timeout)-阻塞调用,最长阻塞事件为timeout。
  • select方法:selectNow(Long timeout)-非阻塞,不管有没有IO事件,都会立刻返回。
  • select方法:返回的整数值,代表发生IO事件的通道数。即上一次select和本次select之间发生事件的通道数。

 

 

你可能感兴趣的:(socket编程)