BIO、NIO、AIO
2024-11-12 11:58 Spiderman25 阅读(76) 评论(0) 收藏 举报
在 Java 中,BIO(Blocking I/O)、NIO(Non-blocking I/O)和 AIO(Asynchronous I/O)是三种不同的 I/O 模型。下面我将给出每种模型的简单示例,以帮助理解它们的区别和用法。
### 1. **BIO(Blocking I/O)**
BIO 是传统的 I/O 模型,在这个模型中,每次操作都需要等到数据完全读取或写入完成才会返回,因此是阻塞式的。
**BIO 示例(简单的客户端-服务器模型)**
**服务器端:**
```java
import java.io.*;
import java.net.*;
public class BIOExampleServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("Server started, waiting for client...");
// 等待客户端连接
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected: " + clientSocket.getInetAddress());
// 通过输入流读取客户端发送的数据
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message = reader.readLine();
System.out.println("Received from client: " + message);
// 发送响应给客户端
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
writer.println("Hello from server!");
// 关闭连接
reader.close();
writer.close();
clientSocket.close();
serverSocket.close();
}
}
```
**客户端:**
```java
import java.io.*;
import java.net.*;
public class BIOExampleClient {
public static void main(String[] args) throws IOException {
// 连接到服务器
Socket socket = new Socket("localhost", 8080);
// 向服务器发送数据
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
writer.println("Hello, server!");
// 从服务器接收响应
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String response = reader.readLine();
System.out.println("Received from server: " + response);
// 关闭连接
writer.close();
reader.close();
socket.close();
}
}
```
### 2. **NIO(Non-blocking I/O)**
NIO 是一种非阻塞 I/O 模型,它使用通道和缓冲区的概念,通过 `Selector` 可以同时监听多个通道,在没有数据可用时,不会阻塞线程。
**NIO 示例(简单的客户端-服务器模型)**
**服务器端:**
```java
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
public class NIOExampleServer {
public static void main(String[] args) throws IOException {
// 打开服务器套接字通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false); // 非阻塞模式
// 打开选择器
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started, waiting for client...");
while (true) {
// 选择有事件发生的通道
selector.select();
var selectedKeys = selector.selectedKeys();
var iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()) {
// 接受客户端连接
SocketChannel clientChannel = serverSocketChannel.accept();
clientChannel.configureBlocking(false); // 非阻塞模式
clientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Client connected: " + clientChannel.getRemoteAddress());
} else if (key.isReadable()) {
// 读取客户端数据
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(256);
int bytesRead = clientChannel.read(buffer);
if (bytesRead == -1) {
clientChannel.close();
} else {
buffer.flip();
System.out.println("Received from client: " + new String(buffer.array(), 0, bytesRead));
// 响应客户端
buffer.clear();
buffer.put("Hello from server!".getBytes());
buffer.flip();
clientChannel.write(buffer);
}
}
}
}
}
}
```
**客户端:**
```java
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
public class NIOExampleClient {
public static void main(String[] args) throws IOException {
// 连接到服务器
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 8080));
socketChannel.configureBlocking(false);
// 发送数据到服务器
String message = "Hello, server!";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
socketChannel.write(buffer);
// 接收服务器响应
buffer.clear();
socketChannel.read(buffer);
buffer.flip();
System.out.println("Received from server: " + new String(buffer.array(), 0, buffer.limit()));
// 关闭连接
socketChannel.close();
}
}
```
### 3. **AIO(Asynchronous I/O)**
AIO 是 Java 7 引入的异步 I/O 模型。它允许在 I/O 操作完成时通过回调通知程序,而不是阻塞线程。AIO 是基于 `AsynchronousChannel` 和回调机制实现的。
**AIO 示例(简单的客户端-服务器模型)**
**服务器端:**
```java
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.concurrent.*;
public class AIOExampleServer {
public static void main(String[] args) throws IOException {
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
System.out.println("Server started, waiting for client...");
// 接收客户端连接
serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel clientChannel, Void attachment) {
// 继续监听其他连接
serverChannel.accept(null, this);
// 读取客户端数据
ByteBuffer buffer = ByteBuffer.allocate(256);
clientChannel.read(buffer, null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer result, Void attachment) {
buffer.flip();
System.out.println("Received from client: " + new String(buffer.array(), 0, result));
// 发送响应
buffer.clear();
buffer.put("Hello from server!".getBytes());
buffer.flip();
clientChannel.write(buffer, null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer result, Void attachment) {
// 响应发送完成
try {
clientChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
// 阻止主线程退出
CountDownLatch latch = new CountDownLatch(1);
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
```
**客户端:**
```java
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.concurrent.*;
public class AIOExampleClient {
public static void main(String[] args) throws Exception {
AsynchronousSocketChannel clientChannel = AsynchronousSocketChannel.open();
Future<Void> future = clientChannel.connect(new InetSocketAddress("localhost", 8080));
future.get(); // 等待连接完成
// 发送数据到服务器
String message = "Hello, server!";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
clientChannel.write(buffer).get();
// 接收服务器响应
buffer.clear();
clientChannel.read(buffer).get();
buffer.flip();
System.out.println("Received from server: " + new String(buffer.array(), 0, buffer.limit()));
// 关闭连接
clientChannel.close();
}
}
```
### 总结
- **BIO**:传统的阻塞 I/O,适用于简单的客户端-服务器模型,但在高并发时效率较低。
- **NIO**:使用非阻塞 I/O,通过通道和选择器实现高效的 I/O 操作,适合需要处理大量并发连接的应用。
- **AIO**:基于回调的异步 I/O,在 I/O 操作完成时通知应用程序,适用于非常高效且复杂的并发模型。
这些模型根据具体的应用场景选择使用。BIO 适合简单的同步应用,NIO 适合高并发的应用,而 AIO 适合对性能要求极高的异步操作。
### 1. **BIO(Blocking I/O)**
BIO 是传统的 I/O 模型,在这个模型中,每次操作都需要等到数据完全读取或写入完成才会返回,因此是阻塞式的。
**BIO 示例(简单的客户端-服务器模型)**
**服务器端:**
```java
import java.io.*;
import java.net.*;
public class BIOExampleServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("Server started, waiting for client...");
// 等待客户端连接
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected: " + clientSocket.getInetAddress());
// 通过输入流读取客户端发送的数据
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message = reader.readLine();
System.out.println("Received from client: " + message);
// 发送响应给客户端
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
writer.println("Hello from server!");
// 关闭连接
reader.close();
writer.close();
clientSocket.close();
serverSocket.close();
}
}
```
**客户端:**
```java
import java.io.*;
import java.net.*;
public class BIOExampleClient {
public static void main(String[] args) throws IOException {
// 连接到服务器
Socket socket = new Socket("localhost", 8080);
// 向服务器发送数据
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
writer.println("Hello, server!");
// 从服务器接收响应
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String response = reader.readLine();
System.out.println("Received from server: " + response);
// 关闭连接
writer.close();
reader.close();
socket.close();
}
}
```
### 2. **NIO(Non-blocking I/O)**
NIO 是一种非阻塞 I/O 模型,它使用通道和缓冲区的概念,通过 `Selector` 可以同时监听多个通道,在没有数据可用时,不会阻塞线程。
**NIO 示例(简单的客户端-服务器模型)**
**服务器端:**
```java
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
public class NIOExampleServer {
public static void main(String[] args) throws IOException {
// 打开服务器套接字通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false); // 非阻塞模式
// 打开选择器
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started, waiting for client...");
while (true) {
// 选择有事件发生的通道
selector.select();
var selectedKeys = selector.selectedKeys();
var iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()) {
// 接受客户端连接
SocketChannel clientChannel = serverSocketChannel.accept();
clientChannel.configureBlocking(false); // 非阻塞模式
clientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Client connected: " + clientChannel.getRemoteAddress());
} else if (key.isReadable()) {
// 读取客户端数据
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(256);
int bytesRead = clientChannel.read(buffer);
if (bytesRead == -1) {
clientChannel.close();
} else {
buffer.flip();
System.out.println("Received from client: " + new String(buffer.array(), 0, bytesRead));
// 响应客户端
buffer.clear();
buffer.put("Hello from server!".getBytes());
buffer.flip();
clientChannel.write(buffer);
}
}
}
}
}
}
```
**客户端:**
```java
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
public class NIOExampleClient {
public static void main(String[] args) throws IOException {
// 连接到服务器
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 8080));
socketChannel.configureBlocking(false);
// 发送数据到服务器
String message = "Hello, server!";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
socketChannel.write(buffer);
// 接收服务器响应
buffer.clear();
socketChannel.read(buffer);
buffer.flip();
System.out.println("Received from server: " + new String(buffer.array(), 0, buffer.limit()));
// 关闭连接
socketChannel.close();
}
}
```
### 3. **AIO(Asynchronous I/O)**
AIO 是 Java 7 引入的异步 I/O 模型。它允许在 I/O 操作完成时通过回调通知程序,而不是阻塞线程。AIO 是基于 `AsynchronousChannel` 和回调机制实现的。
**AIO 示例(简单的客户端-服务器模型)**
**服务器端:**
```java
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.concurrent.*;
public class AIOExampleServer {
public static void main(String[] args) throws IOException {
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
System.out.println("Server started, waiting for client...");
// 接收客户端连接
serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel clientChannel, Void attachment) {
// 继续监听其他连接
serverChannel.accept(null, this);
// 读取客户端数据
ByteBuffer buffer = ByteBuffer.allocate(256);
clientChannel.read(buffer, null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer result, Void attachment) {
buffer.flip();
System.out.println("Received from client: " + new String(buffer.array(), 0, result));
// 发送响应
buffer.clear();
buffer.put("Hello from server!".getBytes());
buffer.flip();
clientChannel.write(buffer, null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer result, Void attachment) {
// 响应发送完成
try {
clientChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
// 阻止主线程退出
CountDownLatch latch = new CountDownLatch(1);
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
```
**客户端:**
```java
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.concurrent.*;
public class AIOExampleClient {
public static void main(String[] args) throws Exception {
AsynchronousSocketChannel clientChannel = AsynchronousSocketChannel.open();
Future<Void> future = clientChannel.connect(new InetSocketAddress("localhost", 8080));
future.get(); // 等待连接完成
// 发送数据到服务器
String message = "Hello, server!";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
clientChannel.write(buffer).get();
// 接收服务器响应
buffer.clear();
clientChannel.read(buffer).get();
buffer.flip();
System.out.println("Received from server: " + new String(buffer.array(), 0, buffer.limit()));
// 关闭连接
clientChannel.close();
}
}
```
### 总结
- **BIO**:传统的阻塞 I/O,适用于简单的客户端-服务器模型,但在高并发时效率较低。
- **NIO**:使用非阻塞 I/O,通过通道和选择器实现高效的 I/O 操作,适合需要处理大量并发连接的应用。
- **AIO**:基于回调的异步 I/O,在 I/O 操作完成时通知应用程序,适用于非常高效且复杂的并发模型。
这些模型根据具体的应用场景选择使用。BIO 适合简单的同步应用,NIO 适合高并发的应用,而 AIO 适合对性能要求极高的异步操作。
浙公网安备 33010602011771号