Selector选择器是什么
Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。
Java NIO的选择器部分,实际上有三个重要的类:
- Selector 选择器,完成主要的选择功能,维护着注册的一组SelectionKey。
- SelectableChannel 记录了一组注册的SelectionKey[]。
- SelectionKey 关联了一个Channel和一个Selector,描述一个Selector和SelectableChannel的关系。并保存有通道所关心的操作。
Selector
更新准备好的SelectionKey,移除isValid()为false的SelectionKey
- select() //阻塞等待,直至一个channel准备好或调用wakeup()才返回
- select(long timeout) //如上,返回条件多了个超时时间
- selectNow() //非阻塞,会立刻返回,没有时返回值=0
- wakeup() //使得Selector返回
SelectionKey
兴趣操作集,通过它就可以知道channel可以去做哪些事了.有4种类型,如下:
- public static final int OP_READ = 1 << 0;
- public static final int OP_ACCEPT = 1 << 4;
- public static final int OP_WRITE = 1 << 2;
- public static final int OP_CONNECT = 1 << 3;
通过SelectionKey.interestOps(int ops)就可以配置这些值
SelectionKey
- SelectionKey.attach(Object ob) //添加附件,另一种方式SelectableChannel.register(Selector sel, int ops, Object att)
- SelectionKey.attachment() //获取附件
- SelectionKey.cancel(),永久的注销键,加入Selector的注销集中,在下次select()时被移除
完整实例
@Test
public void client() throws IOException {
//获取通道
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 7777));
//切换成非阻塞模式
socketChannel.configureBlocking(false);
//分配缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
//发送数据给服务端
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String str = scanner.next();
buffer.put((LocalDateTime.now().toString().getBytes() + ":" + str).getBytes());
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
}
//关闭通道
socketChannel.close();
}
@Test
public void server() throws IOException {
//获取通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//切换非阻塞模式
serverSocketChannel.configureBlocking(false);
//绑定连接
serverSocketChannel.bind(new InetSocketAddress(7777));
//获取选择器
Selector selector = Selector.open();
//将通道注册到选择器
//可以监听的事件类型
//读 SelectionKey.OP_READ 1
//写 SelectionKey.OP_WRITE 4
//连接 SelectionKey.OP_CONNECT 8
//接收SelectionKey.OP_ACCEPT 16
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
//轮询获取选择器上已经准备就绪的事件
while (selector.select() > 0) {
//获取当前选择器中所有注册的选择键(已就绪的监听事件)
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
//获取准备就绪的事件
SelectionKey selectionKey = (SelectionKey) iterator.next();
//判断具体是什么事件准备就绪
if (selectionKey.isAcceptable()) {
//若接收就绪,就获取客户端的连接
SocketChannel socketChannel = serverSocketChannel.accept();
//切换非阻塞模式
socketChannel.configureBlocking(false);
//将该通道注册到选择器上
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) {
//若读就绪,获取当前选择器上读就绪状态的通道
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
//读取数据
ByteBuffer buffer = ByteBuffer.allocate(1024);
int length = 0;
while ((length = socketChannel.read(buffer)) > 0) {
buffer.flip();
System.out.println(new String(buffer.array(), 0, length));
buffer.clear();
}
}
//取消选择键 SelectionKey
iterator.remove();
}
}
}
参考:http://www.cnblogs.com/bronte/articles/1966550.html
http://ifeve.com/selectors/