代码改变世界

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 适合对性能要求极高的异步操作。