介绍
引用的问题 -> BIO本身关心的是读写的过程,如果可以直接读写,就读写;不允许就阻塞读写。Java NIO将上面的读写拆分为准备读写和真正读写两个过程。而java NIO的这两个过程就是通过选择器实现的。所以选择器多了等待就绪,选择执行就绪任务的功能。
选择器执行过程
- 通过open方法程序创建一个系统默认的选择器。
- 使用register方法将一个或者多个可选择通道注册到选择器上(至于注册上去的可选择通道的类型SelectionKey选择键来表示)。
- SelectionKey选择键会标记每个注册到选择器上的通道,然后通过SelectionKey的isReadable、isWritable等方法判断通道是否可读可写;然后就要真正去读写了。
- 使用选择器Selector调用方法select,然后更新选择器键集。至于发生阻塞,是一直阻塞还是阻塞一段时间还是阻塞立即返回就体现在select()、select(time)、selectNow()方法上了。
- 如果通过选择键找到了对应的就绪通道,然后剩下就是缓冲区上读写操作等。
选择键
选择键是选择通道在选择器上的一个注册标记。
1.png
例子
客户端:
public class MyNIOClient {
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
// 完成套接字通道的连接过程
if (socketChannel.finishConnect()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("sunpy".getBytes());
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
}
socketChannel.close();
}
}
服务端:
public class MyNIOServer {
public static void main(String[] args) throws IOException {
ServerSocketChannel seChannel = ServerSocketChannel.open();
seChannel.configureBlocking(false);
seChannel.bind(new InetSocketAddress("127.0.0.1", 9999));
Selector selector = Selector.open();
seChannel.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
// 此键的通道是否已准备好接受新的套接字连接
if (key.isAcceptable()) {
// 返回为之创建此键的通道
ServerSocketChannel channel = (ServerSocketChannel) key.channel();
// 接受到此通道套接字的连接,如果有返回套接字通道,将阻塞
SocketChannel clientChannel = channel.accept();
// 配置为非阻塞
clientChannel.configureBlocking(false);
// 注册到selector,等待连接
clientChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
clientChannel.read(buffer);
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear();
}
// 将键集中操作过的键移出
it.remove();
}
}
}
}
结果:
3.jpg
网友评论