Java Nio 简明教程
Java NIO - Selector
如我们所知,Java NIO 支持从多个通道和缓冲区进行多个事务。因此,为了检查一个或多个 NIO 通道并确定哪些通道已准备好进行数据事务,即读取或写入,Java NIO 提供选择器。
As we know that Java NIO supports multiple transaction from and to channels and buffer.So in order to examine one or more NIO Channel’s, and determine which channels are ready for data transaction i.e reading or writing Java NIO provide Selector.
使用选择器,我们可以让线程知道哪个通道已准备好进行数据写入和读取,并处理特定通道。
With Selector we can make a thread to know that which channel is ready for data writing and reading and could deal that particular channel.
我们可以通过调用其静态方法 open() 来获取选择器实例。在打开选择器后,我们必须向其注册非阻塞模式通道,这将返回 SelectionKey 实例。
We can get selector instance by calling its static method open().After open selector we have to register a non blocking mode channel with it which returns a instance of SelectionKey.
SelectionKey 基本上是可以使用通道执行的操作集合,或者可以说我们可以借助选择器密钥了解通道的状态。
SelectionKey is basically a collection of operations that can be performed with channel or we can say that we could know the state of channel with the help of selection key.
表示选择器密钥通道的主要操作或状态是:
The major operations or state of channel represented by selection key are −
-
SelectionKey.OP_CONNECT − Channel which is ready to connect to server.
-
SelectionKey.OP_ACCEPT − Channel which is ready to accept incoming connections.
-
SelectionKey.OP_READ − Channel which is ready to data read.
-
SelectionKey.OP_WRITE − Channel which is ready to data write.
注册后获得的选择器密钥具有以下几个重要方法:
Selection key obtained after registration has some important methods as mentioned below −
-
attach() − This method is used to attach an object with the key.The main purpose of attaching an object to a channel is to recognizing the same channel.
-
attachment() − This method is used to retain the attached object from the channel.
-
channel() − This method is used to get the channel for which the particular key is created.
-
selector() − This method is used to get the selector for which the particular key is created.
-
isValid() − This method returns weather the key is valid or not.
-
isReadable() − This method states that weather key’s channel is ready for read or not.
-
isWritable() − This method states that weather key’s channel is ready for write or not.
-
isAcceptable() − This method states that weather key’s channel is ready for accepting incoming connection or not.
-
isConnectable() − This method tests whether this key’s channel has either finished, or failed to finish, its socket-connection operation.
-
isAcceptable() − This method tests whether this key’s channel is ready to accept a new socket connection.
-
interestOps() − This method retrieves this key’s interest set.
-
readyOps() − This method retrieves the ready set which is the set of operations the channel is ready for.
通过调用其静态方法 select() ,我们可以从选择器中选择通道。选择器的选择方法被重载为 -
We can select a channel from selector by calling its static method select().Select method of selector is overloaded as −
-
select() − This method blocks the current thread until at least one channel is ready for the events it is registered for.
-
select(long timeout) − This method does the same as select() except it blocks the thread for a maximum of timeout milliseconds (the parameter).
-
selectNow() − This method doesn’t block at all.It returns immediately with whatever channels are ready.
此外,为了离开调用选择方法的阻塞线程,可以在选择器实例中调用 wakeup() 方法,然后在 select() 中等待的线程将立即返回。
Also in order to leave a blocked thread which call out select method,wakeup() method can be called from selector instance after which the thread waiting inside select() will then return immediately.
最后,我们可以通过调用 close() 方法关闭选择器,该方法还会使与此选择器注册的所有 SelectionKey 实例无效,同时关闭选择器。
In last we can close the selector by calling close() method which also invalidates all SelectionKey instances registered with this Selector along with closing the selector.
Example
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class SelectorDemo {
public static void main(String[] args) throws IOException {
String demo_text = "This is a demo String";
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress("localhost", 5454));
serverSocket.configureBlocking(false);
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
ByteBuffer buffer = ByteBuffer.allocate(256);
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
int interestOps = key.interestOps();
System.out.println(interestOps);
if (key.isAcceptable()) {
SocketChannel client = serverSocket.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
client.read(buffer);
if (new String(buffer.array()).trim().equals(demo_text)) {
client.close();
System.out.println("Not accepting client messages anymore");
}
buffer.flip();
client.write(buffer);
buffer.clear();
}
iter.remove();
}
}
}
}