Fork me on GitHub
余鸢

Netty学习-Selector

Selector的基本概念

Selector充当一个注册表,当(注册的)一个Channel状态变化时,你的应用可以通过selector被通知到。可能的状态变化包括:

  • 一个新的Channel被接受,准备好(读写)
  • 一个Channel连接完成
  • 一个Channel有待读取的数据
  • 一个Channel可被写入数据

应用程序响应了这个状态变化后,selector被重置,然后这个过程再不断重复,整个过程就是跑在一个线程上不断检查状态变化并作出响应。

下表列出的常量是类java.nio.channels.SelectionKey定义的位模式(bit pattern)。这些模式可以合起来使用,表明应用程序需要收到哪些状态变化的通知。

名称 描述
OP_ACCEPT 当一个新的连接被接受,一个Channel创建时请求收到通知
OP_CONNECT 当一个连接建立时请求收到通知
OP_READ 当数据已准备好从Channel中被读取时请求收到通知
OP_WRITE 当可以往一个Channel中写入更多数据时请求收到通知。这个用在socket缓冲完全满的情况下,通常发生在当数据传送比远端处理快很多的时候。

Selector:java nio无阻塞io实现的关键。

阻塞io和无阻塞io:

阻塞io是指jdk1.4之前版本面向流的io,服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒 绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。

当并发量大,而后端服务或客户端处理数据慢时就会产生产生大量线程处于等待中,即上述的阻塞。

无阻塞io是使用单线程或者只使用少量的多线程,每个连接共用一个线程,当处于等待(没有事件)的时候线程资源可以释放出来处理别的请求,通过事件驱动模型当有accept/read/write等事件发生后通知(唤醒)主线程分配资源来处理相关事件。java.nio.channels.Selector就是在该模型中事件的观察者,可以将多个SocketChannel的事件注册到一个Selector上,当没有事件发生时Selector处于阻塞状态,当SocketChannel有accept/read/write等事件发生时唤醒Selector。

Selector是使用了单线程模型,主要用来描述事件驱动模型。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.socket().bind(new InetSocketAddress(port));
ssc.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// select()阻塞,等待有事件发生唤醒
int selected = selector.select();
if (selected > 0) {
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey key = selectedKeys.next();
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
// 处理 accept 事件
} else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
// 处理 read 事件
} else if ((key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
// 处理 write 事件
}
selectedKeys.remove();
}
}
}

代码中关键的几个点在:
Selector.open();
selector.select();
阻塞后唤醒可以通过注册在selector上的socket有事件发生 或者 selector.select(timeOut)超时 或者 selector.wakeup()主动唤醒;

源码分析参考地址:http://zhhphappy.iteye.com/blog/2032893