> 文章列表 > 从BIO到NIO、AIO和零拷贝

从BIO到NIO、AIO和零拷贝

从BIO到NIO、AIO和零拷贝

文章目录

  • 从BIO到NIO、AIO和零拷贝
    • BIO
    • NIO
    • AIO
    • 零拷贝
    • 结论

从BIO到NIO、AIO和零拷贝

在JAVA的网络编程方面,BIO、NIO、AIO和零拷贝是我们必须掌握的技术,它们分别代表着不同的网络编程实现方式。

BIO

BIO(Blocking I/O)阻塞式I/O模型是Java网络编程中最基本的一种I/O模型。在BIO模型中,所有的I/O操作都是阻塞的,也就是说,当一个线程调用read()或write()时,该线程会被阻塞,直到有数据可读或写入成功。虽然BIO模型编程简单且易于理解,但是其并发性能很差,因为每个连接都需要独立的线程来处理,随着线程数量的增加,资源消耗也会随之增加,最终导致系统性能下降。

以下是一个简单的BIO模型的例子:

public class BioServer {public static void main(String[] args) {try {ServerSocket serverSocket = new ServerSocket(8080);while (true) {Socket socket = serverSocket.accept();new Thread(new BioHandler(socket)).start();}} catch (IOException e) {e.printStackTrace();}}
}public class BioHandler implements Runnable {private Socket socket;public BioHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg = null;while ((msg = reader.readLine()) != null) {System.out.println(msg);}socket.close();} catch (IOException e) {e.printStackTrace();}}
}

在上面的例子中,当有一个客户端连接到服务器,就会创建一个新线程去处理这个连接请求。虽然使用多线程可以很好的解决单个连接的阻塞问题,但是线程的创建和销毁的开销也是非常大的。

NIO

NIO(Non-blocking I/O)非阻塞式I/O模型是对BIO模型的改进。在NIO模型中,所有的I/O操作都是非阻塞的,因此不需要为每个连接都创建一个独立的线程,而是可以通过一个线程处理多个连接。NIO模型中引入了Selector机制,通过该机制可以实现单线程对多个连接的管理和调度,从而提高了系统的并发性能。

以下是一个简单的NIO模型的例子:

public class NioServer {public static void main(String[] args) throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);serverSocketChannel.bind(new InetSocketAddress(8080));Selector selector = Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();if (key.isAcceptable()) {SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {SocketChannel channel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int read = channel.read(buffer);if (read > 0) {System.out.println(new String(buffer.array(), 0, read));} else if (read == -1) {channel.close();}}iterator.remove();}}}
}

在上面的例子中,我们使用了ServerSocketChannel和SocketChannel来处理客户端连接,而且我们只使用了一个线程来管理多个连接。通过Selector机制,我们可以实现对于多个连接的非阻塞读取和写入。

AIO

AIO(Asynchronous I/O)异步I/O模型是在NIO模型的基础上又做了一些改进,它将I/O操作的具体实现委托给内核,直接由内核进行读写操作,当数据读写完成后再回调到应用层,这样就不需要像BIO、NIO模型那样由用户线程进行数据读取和写入,从而减少了系统调用的次数,充分利用了系统的资源。

以下是一个简单AIO模型的例子:

public class AioServer {public static void main(String[] args) throws IOException, InterruptedException {AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8080));serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {@Overridepublic void completed(AsynchronousSocketChannel channel, Void attachment) {ByteBuffer buffer = ByteBuffer.allocate(1024);channel.read(buffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer result, Void attachment) {System.out.println(new String(buffer.array(), 0, result));}@Overridepublic void failed(Throwable exc, Void attachment) {exc.printStackTrace();}});}@Overridepublic void failed(Throwable exc, Void attachment) {exc.printStackTrace();}});Thread.sleep(Integer.MAX_VALUE);}
}

在上面的例子中,我们使用了AsynchronousServerSocketChannel和AsynchronousSocketChannel来处理客户端连接,同时使用了CompletionHandler机制来处理异步的读写操作。

零拷贝

零拷贝技术指避免CPU从应用缓冲区向内核缓冲区拷贝数据的一种技术。在网络编程领域,零拷贝可以将数据直接从磁盘或网络适配器读入内存中,从而避免了CPU的复制操作,提高了数据传输效率。在JAVA中,可以使用NIO的FileChannel.transferTo()方法来进行零拷贝的操作。

以下是一个简单的零拷贝的代码实例:

public class ZeroCopyDemo {public static void main(String[] args) throws IOException {RandomAccessFile fromFile = new RandomAccessFile("fromfile.txt", "rw");FileChannel fromChannel = fromFile.getChannel();RandomAccessFile toFile = new RandomAccessFile("tofile.txt", "rw");FileChannel toChannel = toFile.getChannel();fromChannel.transferTo(0, fromChannel.size(), toChannel);}
}

在上面的例子中,我们使用了FileChannel.transferTo()方法将一个文件的数据直接传输至另一个文件,完成零拷贝的操作。

结论

通过以上的介绍可知,BIO、NIO、AIO和零拷贝都是JAVA网络编程中非常重要的技术。在实际项目开发过程中,我们需要根据具体的业务场景来选择采用哪种技术,以便最大程度地提高应用程序的性能效率。