Java NIO 总结: Channel 通道

文摘   2024-09-16 22:28   广东  

Java NIO 总结:  NIO技术核心概念

温故知新!Java NIO总结: ByteBuffer缓存

一、Channel的基本概念和作用

在Java NIO中,Channel是一个核心概念,它表示一个打开的连接,可以连接到I/O设备(如磁盘文件、Socket)或者一个支持I/O访问的应用程序。与传统的IO操作相比,NIO通过Channel和Buffer相结合,提高了IO性能和数据传输效率。

Channel是Java NIO中的一个接口,它定义了与I/O设备交互的基本方法,如读取、写入和关闭等。Channel主要有四种类型:FileChannel、SocketChannel、ServerSocketChannel和DatagramChannel,分别对应着文件I/O和网络通信的不同场景。提供一种高效、非阻塞的IO操作方式。通过Channel和Buffer的结合使用,减少了数据在内存和磁盘之间的复制次数,提高了数据传输效率。

二、Channel的工作原理

在Java NIO中,所有的IO操作都是从Channel开始的。读取操作即从Channel读到Buffer,写操作即从Buffer写入Channel。这种数据传输方式减少了数据在内存和磁盘之间的复制次数,提高了数据传输效率。

三、Channel的基本使用

使用FileChannel读取文件的代码:

try (FileChannel fileChannel = new RandomAccessFile("example.txt""r").getChannel()) {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int bytesRead = 0;
    while ((bytesRead = fileChannel.read(buffer)) != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear();
    }
catch (IOException e) {
    e.printStackTrace();
}

使用FileChannel来读取一个文件,并通过ByteBuffer来暂存读取到的数据。

四、Channel的四种类型

1. FileChannel

作用:FileChannel是用于文件的数据读写的通道。它允许应用程序从文件中读取数据,也可以将数据写入文件中。

使用

  • 获取FileChannel:通过RandomAccessFile的getChannel()方法获取。
  • 读取数据:使用read()方法从文件中读取数据到ByteBuffer缓冲区。
  • 写入数据:使用write()方法将数据写入文件。
  • 关闭通道:使用close()方法关闭通道。

代码:

try (FileChannel fileChannel = new RandomAccessFile("example.txt""r").getChannel()) {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int bytesRead = 0;
    while ((bytesRead = fileChannel.read(buffer)) != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear();
    }
catch (IOException e) {
    e.printStackTrace();
}

2. SocketChannel

作用:SocketChannel是用于TCP套接字TCP连接的数据读写的通道。

使用

  • 获取SocketChannel:使用SocketChannel.open()方法创建套接字传输通道。
  • 连接服务器:调用connect()方法连接到服务器。
  • 读取数据:使用read()方法从SocketChannel读取数据到ByteBuffer缓冲区。
  • 写入数据:使用write()方法将数据写入SocketChannel。
  • 关闭通道:使用close()方法关闭通道。

代码:

try (SocketChannel socketChannel = SocketChannel.open()) {
    socketChannel.configureBlocking(false);
    socketChannel.connect(new InetSocketAddress("127.0.0.1"80));
    while (!socketChannel.finishConnect()) {
        // 等待连接完成
    }
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int bytesRead = 0;
    while ((bytesRead = socketChannel.read(buffer)) != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear();
    }
catch (IOException e) {
    e.printStackTrace();
}

3. ServerSocketChannel

作用:ServerSocketChannel是用于监听TCP连接请求的通道,它允许服务器监听新进来的TCP连接,并为每个监听到的请求创建一个SocketChannel。

使用

  • 获取ServerSocketChannel:使用ServerSocketChannel.open()方法创建ServerSocketChannel。
  • 绑定端口:调用bind()方法绑定到特定端口。
  • 监听连接:使用accept()方法接受新连接请求。

代码:

try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
    serverSocketChannel.socket().bind(new InetSocketAddress(9090));
    while (true) {
        SocketChannel socketChannel = serverSocketChannel.accept();
        System.out.println(socketChannel.socket().getRemoteSocketAddress() + "已连接");
    }
catch (IOException e) {
    e.printStackTrace();
}

4. DatagramChannel

作用:DatagramChannel是用于UDP协议的数据读写的通道。

使用

  • 获取DatagramChannel:使用DatagramChannel.open()方法创建DatagramChannel。
  • 绑定端口:调用bind()方法绑定到特定端口。
  • 发送数据:使用send()方法发送数据。
  • 接收数据:使用receive()方法接收数据。

代码:

try (DatagramChannel datagramChannel = DatagramChannel.open()) {
    datagramChannel.bind(new InetSocketAddress(9001));
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    while (true) {
        buffer.clear();
        InetSocketAddress address = (InetSocketAddress) datagramChannel.receive(buffer);
        buffer.flip();
        System.out.println(address.toString() + "发来的消息" + new String(buffer.array(), 0, buffer.limit()));
    }
catch (IOException e) {
    e.printStackTrace();
}

五、通道与通道之间发送数据

通道与通道之间直接发送数据(零拷贝)是Java NIO中的一种优化技术,它允许两个通道之间直接传输数据,避免了数据在用户态和内核态之间的多次拷贝,从而提高了数据传输的效率。

在Java NIO中,零拷贝技术主要通过transferTo()transferFrom()方法实现。这两个方法允许将一个通道中的数据直接传输到另一个通道中,而不需要经过中间的数据拷贝过程。transferTo()方法将文件通道(FileChannel)中的数据传输到套接字通道(SocketChannel)中,transferFrom()方法则相反,将套接字通道中的数据传输到文件通道中。

使用transferTo()方法进行零拷贝文件传输:

// 创建客户端的SocketChannel
SocketChannel socketChannel = SocketChannel.open();

// 连接服务器
socketChannel.connect(new InetSocketAddress("localhost"8080));

// 创建文件通道
FileChannel fileChannel = new RandomAccessFile("source.txt""r").getChannel();

// 使用transferTo()方法将文件通道中的数据传输到套接字通道中
long transferred = fileChannel.transferTo(0, fileChannel.size(), socketChannel);

// 关闭通道
fileChannel.close();
socketChannel.close();

transferTo()方法将文件source.txt中的内容直接传输到服务器的套接字通道中,而不需要将数据先拷贝到用户态缓冲区,然后再拷贝到内核态缓冲区,最后再通过网络传输。这种方式显著提高了数据传输的效率,尤其是在处理大文件时,零拷贝技术能够显著减少数据传输的延迟。

Java NIO 总结: NIO技术核心概念

温故知新!Java NIO总结: ByteBuffer缓存

SpringBoot使用EasyExcel并行导出多个excel文件并压缩zip下载
经典八股:Redis数据结构与底层实现揭秘
玩转同步控制:LockSupport深入解读
90分掌握一门语言:lua脚本基础到高级教程
提升编程效率的利器: Google Guava库中双向映射BitMap
微服务中token鉴权设计的4种方式总结
太强 ! SpringBoot中出入参增强的5种方法 : 加解密、脱敏、格式转换、时间时区处理
太强 ! SpringBoot中优化if-else语句的七种绝佳方法实战
从MySQL行格式原理看:为什么开发规范中不推荐NULL?数据是如何在磁盘上存储的?
关注『 码到三十五 』,日有所获

点赞+转发+在看 就是最大的支持!

码到三十五
主要分享正经的开发技术(原理,架构,实践,源码等),以输出驱动输入;当然偶尔会穿插点生活琐碎,顺便吃个瓜,目的嘛,搞点精准流量,看能不能发发广告。
 最新文章