> 文档中心 > 详述NIO相关组件_Channel、Buffer、Selctor

详述NIO相关组件_Channel、Buffer、Selctor


(一)Channel

channel(通道)是Java NIO相关组件之一。Channel表示IO源与目标打开的连接,我们既可以从通道中读取数据,又可以写数据到通道中。以下是常见的几个Channel

  • FileChannel
    从文件中读写数据
  • DataGramChannel
    通过UDP读写网络中的数据
  • SocketChannel
    通过TCP读写网络中的数据
  • ServerSocketChannel
    可以监听新进来的TCP链接,对每一个新进来的链接都会创建一个socketChannel

Channel的register方法有两个参数,第一个是selector,第二个是通过selector监听对什么感兴趣,参数值选择如下:

  • Connect   某个channel成功链接到另一个服务器称为“链接就绪”。SelectorKey.OP_CONNECT
  • Accept   一个ServerSocketChannel准备好接受新进入的链接称为“接受就绪”.SelectorKey.OP_ACCEP
  • Read    一个有数据可读的channel称为“写就绪”.SelectorKey.OP_READ
  • Write    等待写数据的Channel称为“写就绪”,SelectorKey.OP_WRITE

(二)Buffer

我们知道Channel本身不能直接访问数据,Channel只能与Buffer进行交互。而buffer本质上其实就是一个数组
以下是常见的几个Buffer和其之间的关系
详述NIO相关组件_Channel、Buffer、Selctor
Buffer有几个非常重要的变量,数据的读写都是通过这几个变量的改变来进行的

  • capacity   buffer的最大容量
  • position   当前读写的位置
  • limit     缓冲区现存的元素技术
  • mark    标记position的位置
    详述NIO相关组件_Channel、Buffer、Selctor
    如上图所示,当buffer数组初始化的时候,position指向初始位置,limit与capacity都指向数组末尾。buffer有两种模式,一种为写模式,一种为读模式,默认情况下为写模式。
    当每写一个字节,position位置移动一格,直到channel唯恐,或者position=limit
    详述NIO相关组件_Channel、Buffer、Selctor
    当我们需要读取数据的时候,需要将模式调整为读模式,可以调用buffer.flip()方法。这时limit被赋值为了position,而position则指向起始位置,每读取一个byte,position移动一个位置,直到postion=limit,如图所示
    详述NIO相关组件_Channel、Buffer、Selctor
    当数据读取完毕后,需要再次切换到写模式时,有两种情况
  • 之前的数据已经读取完毕,直接调用clean()方法,position置为0,capacity、limit重新指向最高位。
  • 之前的数据还有剩余,调用compact方法,将会生成一个新的buffer将数据整理压缩。如图所示

详述NIO相关组件_Channel、Buffer、Selctor
我们再来说说mark,其实对于mark来说,其作用只是为了标记当前position的位置,主要是为了和reset()方法配合使用,让position重新回到mark标记的位置。
详述NIO相关组件_Channel、Buffer、Selctor
如图所示,我们当读取到b的时候,调用mark()方法标记当前position位置,然后继续往后面读取数据,当limit=postion的时候调用rest()方法,position位置将回到mark位置,可以重新继续读取。

(三)Selector

这个组件可以说是NIO中最核心的一个组件了,如果没有这个组件,仅采用channel配置buffer所产生的效果其实和NIO是差不多的。该组件用于检查一个或多个NIO Channel的状态是否处于可读,可写。可以实现单线程管理副哦哥channel,相比使用多线程,避免了上下文切换所带来的开销,三组件之间的配合关系如图所示:
详述NIO相关组件_Channel、Buffer、Selctor
使用selector的channel必须是非阻塞的,其实也就是需要继承selectableChannel抽象类,该类有一个configureBlocking()方法,用于使channel处于阻塞模式或非阻塞模式

关于select()方法
selector的select()方法用于选择已经就绪的channel
select()无参,阻塞直到至少有一个channel在你的注册事件上就绪了
select(long timeout)有参,和无参一样,但是最长阻塞时间为指定时间
selectNow: 非阻塞,只要有channel就绪就立即返回