java NIO之SelectedKey

java

    SelectedKey是channel与Selector绑定的标记,每将一个channel注册到一个selector就会产生一个SelectedKey,并将这个SelectedKey放入到Selected的key set中,注意,key set 只能通过这种方式添加,不可以直接添加,但是可以手动移除。

    SelectedKey存在着两个集合,分别是interest set和ready set,二者的元素类型都是整数值,每一位代表一个标记,代表该key对应的channel支持/准备好什么操作。interest set在SelectedKey被创建时(channel注册时)指定,记录了此key对应的channel支持什么操作(accept,write,read,connect等),并且可以在以后通过interestOpt(int)改变;ready set则记录了此SelectedKey已经准备好了什么样的操作,ready set的值由selector设置和更新,不可以由用户去改变。ready set指定的操作说明该种操作已经就绪好,可以实行非阻塞操作了,但是不保证之后该key状态没有被修改(比如channel被关闭),如果之后key状态被改变又没有通过select操作更新(参见java.nio.channels.Selector),则操作可能依然会阻塞线程。

    SelectedKey为每种操作标记都定义了一个静态常量值,但是一个key具体指示什么操作,是由对应的channel决定的,SelectedChannel的各个子类都有自己所支持的操作,如果注册时被制定了不支持的操作,将会发生运行时错误。

    SelectedKey还为应用程序提供了一个附件区,可用于存放上层应用协议相关的数据,比如协议状态等。这个附件区是一个单独的对象,用attach设置,attachment获取。

    SelectedKey本身不是线程安全的,但是,操作它的selector要求实现同步措施,对数据的读写加上不同程度的同步锁。也就是说,同步策略交给具体的selector实现去做。

典型的NIO socket服务端代码如下所示:

public class PlainNioServer {

public void serve(int port) throws IOException {

ServerSocketChannel serverChannel = ServerSocketChannel.open();

serverChannel.configureBlocking(false);

ServerSocket ss = serverChannel.socket();

InetSocketAddress address = new InetSocketAddress(port);

ss.bind(address); //1

Selector selector = Selector.open(); //2

serverChannel.register(selector, SelectionKey.OP_ACCEPT); //3

final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());

for (; ; ) {

try {

selector.select(); //4

} catch (IOException ex) {

ex.printStackTrace();

// handle exception

break;

}

Set<SelectionKey> readyKeys = selector.selectedKeys(); //5

Iterator<SelectionKey> iterator = readyKeys.iterator();

while (iterator.hasNext()) {

SelectionKey key = iterator.next();

iterator.remove();

try {

if (key.isAcceptable()) { //6

ServerSocketChannel server = (ServerSocketChannel) key.channel();

SocketChannel client = server.accept();

client.configureBlocking(false);

client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, msg.duplicate()); //7

System.out.println("Accepted connection from " + client);

}

if (key.isWritable()) { //8

SocketChannel client = (SocketChannel) key.channel();

ByteBuffer buffer = (ByteBuffer) key.attachment();

while (buffer.hasRemaining()) {

if (client.write(buffer) == 0) { //9

break;

}

}

client.close(); //10

}

} catch (IOException ex) {

key.cancel();

try {

key.channel().close();

} catch (IOException cex) { // 在关闭时忽略

}

}

}

}

}

}

以上是 java NIO之SelectedKey 的全部内容, 来源链接: utcz.com/z/391115.html

回到顶部