java nio key_java NIO之SelectedKey

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 classPlainNioServer {public void serve(int port) throwsIOException {

ServerSocketChannel serverChannel=ServerSocketChannel.open();

serverChannel.configureBlocking(false);

ServerSocket ss=serverChannel.socket();

InetSocketAddress address= newInetSocketAddress(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 readyKeys = selector.selectedKeys(); //5

Iterator 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) { //在关闭时忽略

}

}

}

}

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值