NIO 学习(八) selector详解

一、为什么要使用selector

Selector类可用于避免使用非阻塞式客户端中浪费资源忙等方法,考虑一个即时消息服务器,可能有上千个客户端连接到了服务器,在任何时刻都只有少量的消息需要读取和分发,这需要一种方法阻塞等待,直到至少有一个信道可以进行i/o操作。

一个selector实例可以同时检查一组信道的i/o状态,选择器就是一个多路开关选择器,一个选择器能够选择多组信道的i/o操作
使用选择器,需要创建一个selector实例,并将其注册到想要监控的信道上(通过信道的方法实现),调用选择器的select方法,改方法会阻塞等待,直到有一个或更多的信道准备好了i/o操作。
在一个单独的线程中,通过调用select方法能检查多个信道是否准备好进行i/o操作,和可进行i/o操作的信道的数量,没有返回0

二、selector的创建和关闭

static Selector open();

boolean isOpen()

void close();

调用Selector的open工厂方法可以创建一个选择器实例,选择器的状态是打开或者关闭的,创建选择器的状态是打开的,并保存该状态,直到调用close方法关闭,isOpen方法检查选择器是否关闭

三、将selector注册到信道channel上

每个选择器都有一组关联的信道,选择器对这些信道上感兴趣的i/o操作进行监听。

Selector和channel的关联,可以视作是桥梁,由一个selectionkey实例表示

(一个selector可以注册到多个channel上,因而一个selector可以有多个selectionkey)

Selectionkey维护了一个信道上感兴趣的操纵类型信息,并将这些信息存放在一个int的位图中(bitmap),该int型数据的每一位都有相应的意义

SelectionKey类中的常量定义了信道上可能感兴趣的操作类型(称之为key的兴趣集),每个这种常量都是只有一位设置为1的位掩码

表示如下:SelectionKey的兴趣操作集


OP_ACCEPT:接受连接   OP_CONNECT:请求连接

OP_READ:信道数据可读 OP_WRITE:可写

通过对OP_ACCEPT,OP_CONNECT,OP_READ,OP_WRITE中常量进行按位OR,构造出一个位向量指定一组操作

例如:一个读写操作的兴趣集表示为: OP_READ|OP_WRITE

InterestOps() :返回一个int型的位图,该位图中设置为1的每一位都指示了信道上需要监听的一种操作。

(例如OP_READ,OP_WRITE.....)

interestOps(int ops) 一个位图为参数,指定了要监听信道上的那些操作。

需要注意的是,任何对key兴趣集的改变,都在下次调用select方法时候生效

SocketChannel,ServerSocketChannel:注册selector

 SelectionKey register(selector, int ops);

ops:指的是key的兴趣集

SelectionKey register(selector,int ops,Object attachment);

ops:指的是兴趣集,attachment指的是key携带的附件对象

int Validops():返回的是信道的兴趣集

IsRegistered方法检查信道是否注册了选择器

Keyfor方法与第一次调用register方法返回的是同一个selectionKey实例,除非信道没有注册给定的选择器。

通过register将选择器注册到信道上,注册过程中存储的int类型数据,指定了信道的初始兴趣集

对于,ServerSocketChannel来说, accept是唯一有效的操作,而socketChannel,有效操作包括读,写,和连接。

一个信道可能只会注册一个选择器,一个信道对同一个selector的register操作,是对信道兴趣集的修改

下面注册一个信道,支持读写操作。

SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);

键selectionKey的获取和取消

Selector selector()
SelectableChannel channel()
Void cancel()
键selectionKey关联的选择器和信道channel的实例,可以通过selector(),channel()获取,

selectionKey的cancel将键注销,放入到选择器的注销集中,并在下次调用select方法的时候从键集中移除,同时这个key关联的信道也不会再被监听。


这个图,直观的看到,键集(key set)中有 选择键集(selected key set),和注销键集(cancelled key set)

interset sets表示兴趣集(write,read,accept,connect)

选取和识别就绪的信道

在信道注册选择器后,并标识了信道的兴趣操作集,选择器那端,只要等待有合适的i/o操作,就可以操作信道

int select()
int select(long timeout)
int selectNow()
Selector wakeup()

无参的select方法,返回已注册信道中准备就绪的信道总数,和其他select方法的区别是:

1.无参数的select方法会阻塞等待,直到至少有一个注册信道中兴趣级的操作准备就绪,
或有别的线程调用了该选择器的wakeup方法(这种情况下select返回0)

2. 有参数的select方法会阻塞等待,直到至少有一个信道准备就绪,或等待时间超过了指定的毫秒数(正数),或者有另一个线程调用其 wakeup()方法
3. selectNow方法是一个非阻塞版本,总是立即返回,如果没有信道准备就绪,则返回0
4. wakeup方法使得当前阻塞的任何一种select方法立即返回;如果当前没有select方法阻塞,下一次调用这三种方法的任何一个都将立即返回。

选取键集

Keys() :返回所有注册的所有键,返回的键都是不可修改的selectedKeys():返回上次调用select方法时,被选中的已准备好进行I/O操作的键。,返回的键是可以修改的。

Iterator<SelectionKey> iterator = selector.keys().iterator();
			while(iterator.hasNext()){
				SelectionKey next = iterator.next();
				if(next.isValid()){
					//do i/o ....
				}
			}

查找可用的信道

SelectionKey:查找就绪的I/O操作
Int readOps() :以位图的形式返回所有准备就绪的操作集
//检查各种操作是否可用
Boolean isAcceptable()
Boolean isConnectable()
Boolean isReadable()
Boolean isWritable()

例如:查看键关联的信道上是否有正在等待的读操作
if((next.readyOps()&SelectionKey.OP_READ)!=0){} 或者使用isReadable()

Note:

选择器中的已选键集中的键,以及每个键中准备就绪的操作,都是由select()方法确定的。

随着时间的推进,这些信息可能会过时,其他线程可能会处理准备就绪的I/O操作,同时,键也不是永远存在的。当其关联的信道或选择器关闭时候,键也将失效。

调用cancel也可以将键设置为无效,isvalid方法可以检测一个键的有效性,无效的键将添加到选择器的注销键集中,并在下次调用select方法或close方法时候,从键集中移除。

信道附件

 当一个信道准备好进行I/O操作时候,通常还需要额外的信息来处理请求。

例如,在回显协议中,当客户端信道准备好写操作时,就需要有数据可写。当然,我们所需要的可写数据是由之前同一个信道上的读操作收集的,但是在其可写之前,这些数据存放在位置

如果一个消息一次传来了多个字节,需要保存已接收的部分消息,知道整个消息接收完成,这两种情况都需要维护每个信道的状态信息。

 Selectionkey使用附件保存每个信道的状态。

SelectionKey; 查找准备就绪的I/O操作

Attach(object ob): 每个键可以有一个附件,数据类型只能是object类型,附件可以在信道第一次调用register方法时候与之关联,或者后来使用attach方法直接添加到键上。

Attachment(): 直接访问键的附件。






  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值