详细讲解一下java里NIO的选择器
时间: 2023-05-26 16:06:25 浏览: 69
Java NIO(New IO)的选择器是一种可以选择一组套接字通信的对象。它是非阻塞IO的基础。它使您可以实现一个线程处理多个通道,从而提高系统的可扩展性和性能。
选择器定义了一个可以监控的通道集合,它将通道转换为这些通道的支持的IO操作之一。它提供了套接字通信的异步框架,以及支持多种通道类型的IO操作(如TCP,UDP和文件I / O)。
在选择器中,您可以注册多个通道,并将它们添加到集合中。选择器将对所有这些通道进行检查,并且仅在通道已准备好执行所请求的操作时才返回。这个准备好的通道的集合被称为“选择键集”。每个选择键表示通道和将要进行的IO操作之间的关系。
选择器是Java NIO的核心组件之一,并且是非阻塞IO的基础。使用它来监控网络套接字通信可以大大提高应用程序的性能和可扩展性。
相关问题
详细讲解java里nio的Channel
Java NIO(New Input Output)是Java SE 1.4中引入的一个新的IO API,它可以提供比传统的Java IO更高效的I/O操作。
在Java NIO中,最核心的概念是Channel(通道)。Channel是用于在Java NIO中进行I/O操作的对象,可以被打开或关闭,并且可以读取或写入数据。
通常情况下,可以通过调用Channel实现读取和写入数据。Channel可以分为以下几类:
1. FileChannel
FileChannel用于在文件中读取和写入数据。
在操作FileChannel时,需要首先通过FileInputStream或FileOutputStream获取文件的输入和输出流,然后通过调用getChannel()方法获取FileChannel对象。
示例:
```
FileInputStream fis = new FileInputStream("test.txt");
FileChannel channel = fis.getChannel();
```
2. SocketChannel
SocketChannel用于通过网络读取和写入数据。
在操作SocketChannel时,需要创建一个SocketChannel对象,并将其连接到一个远程服务器,然后调用read()和write()方法实现数据的读取和写入。
示例:
```
SocketChannel channel = SocketChannel.open();
channel.connect(new InetSocketAddress("www.google.com", 80));
```
3. DatagramChannel
DatagramChannel用于通过UDP连接读取和写入数据。
在操作DatagramChannel时,需要创建一个DatagramChannel对象,并绑定到一个本地端口号,然后调用read()和write()方法实现数据的读取和写入。
示例:
```
DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(9999));
```
4. ServerSocketChannel
ServerSocketChannel用于监听客户端的连接请求。
在操作ServerSocketChannel时,需要创建一个ServerSocketChannel对象,并绑定到一个本地端口号,然后调用accept()方法等待客户端的连接请求。
示例:
```
ServerSocketChannel channel = ServerSocketChannel.open();
channel.socket().bind(new InetSocketAddress(9999));
SocketChannel socketChannel = channel.accept();
```
总结来说,Channel是Java NIO库中最重要的概念之一,它提供了各种不同类型的Channel,可以帮助我们轻松地实现不同类型的I/O操作。通常情况下,在进行I/O操作时,我们都需要借助Channel来完成。
java nio中选择器如何让channel的isReadable变为true
在Java NIO中,选择器(Selector)并不能直接让通道(Channel)的`isReadable()`方法返回`true`。选择器的作用是监听通道上的事件,并在事件发生时进行处理。当通道上有可读事件时,选择器会将该通道的`isReadable()`方法返回`true`。
具体来说,当服务器端将一个通道注册到选择器上,并监听`OP_READ`事件时,如果有客户端向该通道发送数据,选择器就会将该通道的`isReadable()`方法返回`true`,然后服务器端就可以读取客户端发送的数据了。
以下是一个简单的示例代码,演示如何使用选择器监听通道事件:
```
// 创建选择器
Selector selector = Selector.open();
// 创建服务器Socket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.socket().bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);
// 将通道注册到选择器,并监听OP_READ事件
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// 阻塞等待事件
selector.select();
// 处理事件
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = keys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
// 处理连接事件
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 处理可读事件
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = client.read(buffer);
if (len > 0) {
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String message = new String(bytes);
System.out.println("Received message: " + message);
}
}
keyIterator.remove();
}
}
```
在上述代码中,服务器端将服务器Socket通道注册到选择器上,并监听`OP_ACCEPT`事件。当有客户端连接服务器时,选择器就会将该通道的`isAcceptable()`方法返回`true`,服务器端就可以接受客户端的连接了。当客户端发送数据时,选择器就会将该通道的`isReadable()`方法返回`true`,服务器端就可以读取客户端发送的数据了。