SelectionKey
是 Java NIO 中的一个重要类,用于表示一个通道在 Selector
上的注册关系。它包含了通道的状态信息和感兴趣的事件类型。SelectionKey
是使用 Selector
时的核心组件之一,因为它帮助管理和识别通道的 I/O事件。
SelectionKey
的基本概念
- 通道(Channel) :代表一个可以进行 I/O 操作的实体,如
SocketChannel
、ServerSocketChannel
等。 - 选择器(Selector):用于监视多个通道上的 I/O事件。
- 选择键(SelectionKey) :表示一个通道在
Selector
上的注册,包含该通道的事件兴趣和状态。
SelectionKey
的常量
SelectionKey
使用了一些常量来表示通道的不同事件类型:
OP_READ
:表示通道中有数据可读。OP_WRITE
:表示通道可以写数据。OP_CONNECT
:表示连接操作已经完成。OP_ACCEPT
:表示服务器通道已准备好接受新的连接。
这些常量是位掩码,可以组合使用。例如,OP_READ | OP_WRITE
表示对读和写事件都感兴趣。
SelectionKey
的主要方法
-
interestOps():
javaint interestSet = selectionKey.interestOps();
返回当前选择键的兴趣集,即通道感兴趣的操作。
-
interestOps(int ops):
javaselectionKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
设置通道的兴趣集,指定对哪些操作感兴趣。
-
readyOps():
javaint readySet = selectionKey.readyOps();
返回通道已经准备好的操作集。
-
channel():
javaSelectableChannel channel = selectionKey.channel();
返回与此选择键关联的通道。
-
selector():
javaSelector selector = selectionKey.selector();
返回生成此选择键的选择器。
-
isValid():
javaboolean valid = selectionKey.isValid();
检查选择键是否仍然有效。
-
cancel():
javaselectionKey.cancel();
取消选择键,使其无效。
-
attach(Object obj) 和 attachment():
javaselectionKey.attach(someObject); Object attached = selectionKey.attachment();
可以将一个对象附加到选择键上,便于在处理事件时访问相关数据。
使用 SelectionKey
在使用 Selector
进行非阻塞 I/O 操作时,SelectionKey
用于识别哪些通道已经准备好进行 I/O 操作,并获取相关的通道和附加信息。
示例
以下是一个简单的使用 SelectionKey
的示例:
java
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(256);
client.read(buffer);
// 处理读取的数据
}
keyIterator.remove();
}
}
注意事项
- 有效性 :在处理完一个
SelectionKey
后,通常需要调用keyIterator.remove()
来从集合中移除它,以避免重复处理。 - 附加对象 :可以通过
attach()
和attachment()
方法将上下文信息附加到选择键上,方便在事件处理时使用。 - 取消键 :当通道不再需要时,可以调用
cancel()
方法取消选择键。
SelectionKey
是 Java NIO 中实现高效非阻塞 I/O 操作的关键工具之一,通过它可以有效地管理和处理多个通道的事件。