面试题答案
一键面试在Java NIO网络编程中,使用以下机制和核心类来达成非阻塞I/O操作:
- Selector(选择器):它是Java NIO实现非阻塞I/O的关键。Selector可以检测多个注册的通道上是否有事件发生(如连接就绪、数据可读等),如果有事件发生,便获取事件然后进行相应的处理。这样可以使用一个线程来管理多个通道,从而实现非阻塞I/O。
- Channel(通道):与传统I/O中的流不同,通道是双向的,可以读也可以写,并且支持非阻塞操作。主要的通道类型有
SocketChannel
(用于TCP连接)、ServerSocketChannel
(用于监听TCP连接)、DatagramChannel
(用于UDP通信)。 - Buffer(缓冲区):用于和通道进行交互。数据从通道读入缓冲区,从缓冲区写入通道。常见的缓冲区类型有
ByteBuffer
、CharBuffer
等。
示例代码如下:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
private Selector selector;
public NioServer(int port) throws IOException {
// 创建ServerSocketChannel并配置为非阻塞模式
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(port));
// 创建Selector
selector = Selector.open();
// 将ServerSocketChannel注册到Selector上,监听连接事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started on port " + port);
}
public void listen() throws IOException {
while (true) {
// 等待事件发生,这里会阻塞直到有事件发生
int readyChannels = selector.select();
if (readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
// 处理新的连接
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
// 将新的SocketChannel注册到Selector上,监听读事件
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 处理读事件
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = socketChannel.read(buffer);
if (bytesRead > 0) {
buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
String message = new String(data);
System.out.println("Received: " + message);
}
}
keyIterator.remove();
}
}
}
public static void main(String[] args) {
try {
NioServer server = new NioServer(8080);
server.listen();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上述代码中:
- 使用
ServerSocketChannel
创建服务器端通道,并配置为非阻塞模式。 - 通过
Selector
监听ServerSocketChannel
的连接事件(OP_ACCEPT
)。 - 当有新连接到来时,接受连接并将新的
SocketChannel
注册到Selector
上监听读事件(OP_READ
)。 - 当有可读事件发生时,从
SocketChannel
读取数据到ByteBuffer
中进行处理。