
目录
-
- [一、什么是NIO Channel?](#一、什么是NIO Channel?)
- 二、常见的Channel组件及其用法
-
- [1. FileChannel](#1. FileChannel)
- [2. SocketChannel](#2. SocketChannel)
- [3. ServerSocketChannel](#3. ServerSocketChannel)
- [4. DatagramChannel](#4. DatagramChannel)
🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解 Redis主从复制 请看 : Redis主从复制:告别单身Redis!
其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】...等
如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning
这篇文章让我来详细讲解一下Java NIO中的Channel
(通道)组件。
一、什么是NIO Channel?
看本篇文章之前可以先看看NIO是啥:NIO,看完你就懂了!
在Java NIO(New I/O)模型中,Channel
扮演着核心角色。可以将其理解为一个连接到能够执行I/O操作的实体(如文件、网络套接字)的开放连接或通道 。它类似于传统Java I/O中的Stream
(流),但有几个关键区别:
- 双向性 :传统的
InputStream
只能读,OutputStream
只能写。而Channel
通常是双向的,可以同时进行读和写操作(具体取决于通道类型,例如FileChannel
)。 - 与Buffer交互 :
Channel
本身不直接存储数据。所有数据读写都必须通过Buffer
对象进行。数据总是先从Channel
读入Buffer
,或者从Buffer
写入Channel
。 - 异步/非阻塞支持 :
Channel
可以工作在阻塞(Blocking)模式或非阻塞(Non-Blocking)模式下。非阻塞模式是NIO实现高并发、高性能网络应用的关键,通常与Selector
(选择器)一起使用。 - 底层连接 :
Channel
代表了与操作系统底层I/O服务的直接连接。
可以把Channel
想象成数据传输的管道,而Buffer
是运载数据的卡车。卡车(Buffer)在管道(Channel)中来回运输数据。
二、常见的Channel组件及其用法
Java NIO提供了多种Channel
实现,用于处理不同类型的I/O。以下是一些最常见的:
FileChannel
: 用于文件I/O。SocketChannel
: 用于TCP网络通信的客户端。ServerSocketChannel
: 用于TCP网络通信的服务器端,监听并接受连接。DatagramChannel
: 用于UDP网络通信。
下面我们逐一详细讲解:
1. FileChannel
FileChannel
是用于读、写、映射和操作文件的通道。它是唯一保证始终阻塞,不能配置为非阻塞模式的常用通道。
特点:
- 可以从文件的任何位置读写数据(随机访问)。
- 可以将文件区域直接映射到内存(MappedByteBuffer),实现更快的I/O(内存映射文件)。
- 可以实现通道之间的数据直接传输(零拷贝,Zero-Copy),效率很高。
- 线程安全。
如何获取FileChannel
:
- 通过
FileInputStream
的getChannel()
方法。 - 通过
FileOutputStream
的getChannel()
方法。 - 通过
RandomAccessFile
的getChannel()
方法。 - (推荐) 使用
FileChannel.open(Path path, OpenOption... options)
静态工厂方法。
常用方法:
read(ByteBuffer dst)
: 从通道读取数据到Buffer。返回读取的字节数,或-1表示到达文件末尾。write(ByteBuffer src)
: 将Buffer中的数据写入通道。返回写入的字节数。position()
: 返回此通道的文件位置。position(long newPosition)
: 设置此通道的文件位置。size()
: 返回此通道关联文件的当前大小。truncate(long size)
: 将此通道的文件截断为给定大小。force(boolean metaData)
: 强制将通道的所有更新写入存储设备。map(FileChannel.MapMode mode, long position, long size)
: 将此通道的文件区域直接映射到内存中。transferTo(long position, long count, WritableByteChannel target)
: 将字节从此通道的文件传输到给定的可写字节通道(高效的文件复制)。transferFrom(ReadableByteChannel src, long position, long count)
: 将字节从给定的可读字节通道传输到此通道的文件(高效的文件复制)。
示例:使用FileChannel
读取文件
java
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileChannelReadExample {
public static void main(String[] args) {
Path filePath = Paths.get("example.txt"); // 假设存在一个 example.txt 文件
// 使用 try-with-resources 确保通道被关闭
try (FileChannel fileChannel = FileChannel.open(filePath, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配一个1KB的缓冲区
System.out.println("Reading from file: " + filePath);
int bytesRead;
while ((bytesRead = fileChannel.read(buffer)) != -1) { // 从通道读数据到缓冲区
System.out.println("Read " + bytesRead + " bytes.");
// 切换Buffer到读模式
buffer.flip();
// 处理缓冲区中的数据 (这里简单地打印出来)
// 使用 Charset 将字节解码为字符
System.out.print(StandardCharsets.UTF_8.decode(buffer));
// 清空/重置Buffer,为下一次读做准备
buffer.clear(); // 或者 buffer.compact(); 如果想保留未读数据
}
System.out.println("\nEnd of file reached.");
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
e.printStackTrace();
}
}
}
// 需要先创建一个 example.txt 文件,并写入一些内容,例如:
// Hello, Java NIO FileChannel!
// This is a test file.
示例:使用FileChannel
写入文件
java
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileChannelWriteExample {
public static void main(String[] args) {
Path filePath = Paths.get("output.txt");
String dataToWrite = "Writing using Java NIO FileChannel.\nLine 2.";
// 使用 try-with-resources
try (FileChannel fileChannel = FileChannel.open(filePath,
StandardOpenOption.WRITE, // 允许写入
StandardOpenOption.CREATE, // 如果文件不存在则创建
StandardOpenOption.TRUNCATE_EXISTING)) { // 如果文件存在则清空内容
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 将字符串数据放入缓冲区
buffer.put(dataToWrite.getBytes(StandardCharsets.UTF_8));
// 切换Buffer到读模式(写出模式)
buffer.flip();
System.out.println("Writing to file: " + filePath);
while (buffer.hasRemaining()) {
int bytesWritten = fileChannel.write(buffer); // 将缓冲区数据写入通道
System.out.println("Wrote " + bytesWritten + " bytes.");
}
System.out.println("Finished writing.");
} catch (IOException e) {
System.err.println("Error writing file: " + e.getMessage());
e.printStackTrace();
}
}
}
示例:使用transferTo
高效复制文件
java
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileChannelTransferExample {
public static void main(String[] args) {
Path sourcePath = Paths.get("example.txt"); // 源文件
Path destPath = Paths.get("example_copy.txt"); // 目标文件
try (FileChannel sourceChannel = FileChannel.open(sourcePath, StandardOpenOption.READ);
FileChannel destChannel = FileChannel.open(destPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
long position = 0;
long count = sourceChannel.size();
System.out.println("Starting file transfer...");
long bytesTransferred = sourceChannel.transferTo(position, count, destChannel);
// 或者使用 destChannel.transferFrom(sourceChannel, position, count);
System.out.println("Transferred " + bytesTransferred + " bytes from " + sourcePath + " to " + destPath);
} catch (IOException e) {
System.err.println("Error during file transfer: " + e.getMessage());
e.printStackTrace();
}
}
}
2. SocketChannel
SocketChannel
用于TCP网络连接的客户端。它可以工作在阻塞或非阻塞模式下。
特点:
- 用于发起TCP连接到服务器。
- 可以进行读写操作。
- 可以配置为非阻塞模式,与
Selector
配合使用,实现单线程处理多个连接。
如何获取SocketChannel
:
SocketChannel.open()
: 创建一个未连接的SocketChannel
。SocketChannel.open(SocketAddress remote)
: 创建并直接连接到指定地址。
常用方法:
connect(SocketAddress remote)
: 连接到远程地址(非阻塞模式下立即返回,可能未完成连接)。finishConnect()
: 完成非阻塞连接过程。如果连接成功返回true
,如果仍在进行中返回false
,如果失败则抛出异常。isConnected()
: 检查是否已连接。read(ByteBuffer dst)
: 从通道读取数据到Buffer。write(ByteBuffer src)
: 将Buffer中的数据写入通道。configureBlocking(boolean block)
: 设置阻塞/非阻塞模式。true
为阻塞(默认),false
为非阻塞。register(Selector sel, int ops)
: 将通道注册到Selector
上,监听指定事件(如SelectionKey.OP_CONNECT
,OP_READ
,OP_WRITE
)。close()
: 关闭连接。
示例:阻塞模式的SocketChannel
客户端
java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
public class BlockingSocketClient {
public static void main(String[] args) {
String hostname = "localhost"; // 服务器地址
int port = 9090; // 服务器端口
try (SocketChannel socketChannel = SocketChannel.open()) {
// 连接服务器 (阻塞模式下会等待连接成功或失败)
System.out.println("Connecting to " + hostname + ":" + port);
socketChannel.connect(new InetSocketAddress(hostname, port));
System.out.println("Connection established.");
// 发送数据
String message = "Hello from NIO Client!";
ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));
System.out.println("Sending message: " + message);
while (writeBuffer.hasRemaining()) {
socketChannel.write(writeBuffer);
}
// 接收数据
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int bytesRead = socketChannel.read(readBuffer);
if (bytesRead > 0) {
readBuffer.flip();
byte[] receivedBytes = new byte[readBuffer.remaining()];
readBuffer.get(receivedBytes);
String response = new String(receivedBytes, StandardCharsets.UTF_8);
System.out.println("Received response: " + response);
} else if (bytesRead == -1) {
System.out.println("Server closed connection.");
}
System.out.println("Closing connection.");
} catch (IOException e) {
System.err.println("Client error: " + e.getMessage());
e.printStackTrace();
}
}
}
// 这个例子需要一个监听在 localhost:9090 的服务器来响应。
示例:非阻塞模式SocketChannel
(概念,通常与Selector配合)
非阻塞模式的SocketChannel
通常与Selector
一起使用,这里只展示配置和连接部分:
java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
public class NonBlockingSocketClientConcept {
public static void main(String[] args) {
String hostname = "localhost";
int port = 9090;
try {
// 1. 创建 Selector 和 SocketChannel
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
// 2. 配置为非阻塞模式
socketChannel.configureBlocking(false);
// 3. 发起连接 (非阻塞,立即返回)
boolean connected = socketChannel.connect(new InetSocketAddress(hostname, port));
System.out.println("Initiating connection (non-blocking)...");
if (connected) {
System.out.println("Connection established immediately.");
// 立即连接成功(少见),可以直接注册读写事件
socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
} else {
// 连接尚未完成,注册 OP_CONNECT 事件,等待连接完成
System.out.println("Connection pending, registering OP_CONNECT.");
socketChannel.register(selector, SelectionKey.OP_CONNECT);
}
// --- 之后进入 Selector 循环 ---
// while (true) {
// selector.select(); // 阻塞等待事件
// Set<SelectionKey> selectedKeys = selector.selectedKeys();
// Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
//
// while (keyIterator.hasNext()) {
// SelectionKey key = keyIterator.next();
// if (key.isConnectable()) {
// // 连接完成事件
// handleConnect(key, selector);
// } else if (key.isReadable()) {
// // 可读事件
// handleRead(key);
// } else if (key.isWritable()) {
// // 可写事件
// handleWrite(key);
// }
// keyIterator.remove();
// }
// }
// --- Selector 循环结束 ---
// (实际应用中,Selector 循环会处理连接、读写,并在适当时候关闭 channel 和 selector)
System.out.println("Selector loop would start here (conceptual).");
// 在实际应用中关闭资源
// socketChannel.close();
// selector.close();
} catch (IOException e) {
System.err.println("Client error: " + e.getMessage());
e.printStackTrace();
}
}
// 辅助方法 (仅为演示)
private static void handleConnect(SelectionKey key, Selector selector) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
if (channel.finishConnect()) {
System.out.println("Connection successfully established.");
// 连接成功,现在可以注册读写事件了
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
} else {
System.err.println("Failed to finish connection.");
key.cancel(); // 取消注册
channel.close();
}
}
// handleRead 和 handleWrite 方法省略
}
3. ServerSocketChannel
ServerSocketChannel
用于TCP网络连接的服务器端。它负责监听指定端口上的连接请求,并为每个接受的连接创建一个SocketChannel
。它也可以配置为阻塞或非阻塞模式。
特点:
- 监听入站TCP连接。
- 为每个接受的连接创建一个
SocketChannel
。 - 可以配置为非阻塞模式,与
Selector
配合实现高并发服务器。
如何获取ServerSocketChannel
:
ServerSocketChannel.open()
: 创建一个ServerSocketChannel
。
常用方法:
bind(SocketAddress local)
: 将通道的套接字绑定到本地地址并开始监听。accept()
: 接受一个连接。在阻塞模式 下,此方法会阻塞直到有连接进来。在非阻塞模式 下,如果没有待处理的连接,它会立即返回null
。返回的是代表客户端连接的SocketChannel
。configureBlocking(boolean block)
: 设置阻塞/非阻塞模式。register(Selector sel, int ops)
: 将通道(通常是自身,监听OP_ACCEPT
事件)注册到Selector
。close()
: 关闭监听。
示例:阻塞模式的ServerSocketChannel
java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
public class BlockingServerSocket {
public static void main(String[] args) {
int port = 9090;
try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
// 绑定端口并开始监听
serverSocketChannel.bind(new InetSocketAddress(port));
System.out.println("Server started. Listening on port " + port + " (Blocking Mode)");
while (true) { // 无限循环接受连接
System.out.println("Waiting for a new connection...");
// 阻塞,直到有客户端连接进来
SocketChannel clientChannel = serverSocketChannel.accept();
System.out.println("Accepted connection from: " + clientChannel.getRemoteAddress());
// 为每个客户端创建一个新线程处理(简单示例,非最佳实践)
new Thread(() -> handleClient(clientChannel)).start();
}
} catch (IOException e) {
System.err.println("Server error: " + e.getMessage());
e.printStackTrace();
}
}
private static void handleClient(SocketChannel clientChannel) {
try (SocketChannel channel = clientChannel) { // 使用 try-with-resources
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(buffer); // 读取客户端数据
if (bytesRead > 0) {
buffer.flip();
byte[] receivedBytes = new byte[buffer.remaining()];
buffer.get(receivedBytes);
String message = new String(receivedBytes, StandardCharsets.UTF_8);
System.out.println("Received from client " + channel.getRemoteAddress() + ": " + message);
// 回显给客户端
String response = "Server received: " + message;
ByteBuffer writeBuffer = ByteBuffer.wrap(response.getBytes(StandardCharsets.UTF_8));
while (writeBuffer.hasRemaining()) {
channel.write(writeBuffer);
}
System.out.println("Sent response to client " + channel.getRemoteAddress());
} else if (bytesRead == -1) {
System.out.println("Client " + channel.getRemoteAddress() + " closed connection.");
}
} catch (IOException e) {
try {
System.err.println("Error handling client " + clientChannel.getRemoteAddress() + ": " + e.getMessage());
} catch (IOException ignored) {
System.err.println("Error handling client (address unavailable): " + e.getMessage());
}
} finally {
System.out.println("Finished handling client " ); // 地址可能已不可用
}
}
}
示例:非阻塞模式ServerSocketChannel
(概念,通常与Selector配合)
java
import java.io.IOException;
import java.net.InetSocketAddress;
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 NonBlockingServerSocketConcept {
public static void main(String[] args) {
int port = 9090;
try {
// 1. 创建 Selector 和 ServerSocketChannel
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 2. 配置为非阻塞模式
serverSocketChannel.configureBlocking(false);
// 3. 绑定端口
serverSocketChannel.bind(new InetSocketAddress(port));
System.out.println("Server started. Listening on port " + port + " (Non-Blocking Mode)");
// 4. 将 ServerSocketChannel 注册到 Selector,监听 OP_ACCEPT 事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Waiting for events...");
// --- 进入 Selector 循环 ---
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 serverChannel = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = serverChannel.accept(); // 接受连接 (非阻塞)
if (clientChannel != null) {
clientChannel.configureBlocking(false); // 将接受的客户端Channel也设为非阻塞
// 将新的客户端Channel注册到Selector,监听读事件
clientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Accepted new connection from: " + clientChannel.getRemoteAddress());
}
} else if (key.isReadable()) {
// 有客户端Channel可读
// handleRead(key); // 调用处理读取的方法
System.out.println("Readable event for channel: " + key.channel());
// 在这里读取数据...
// 如果读取完毕或连接关闭,需要 key.cancel() 和 channel.close()
} else if (key.isWritable()) {
// 有客户端Channel可写
// handleWrite(key); // 调用处理写入的方法
System.out.println("Writable event for channel: " + key.channel());
// 在这里写入数据...
// 写完数据后,可能需要取消 OP_WRITE 监听: key.interestOps(SelectionKey.OP_READ);
}
keyIterator.remove(); // 处理完后移除Key,防止重复处理
}
}
// --- Selector 循环结束 ---
} catch (IOException e) {
System.err.println("Server error: " + e.getMessage());
e.printStackTrace();
}
// 实际应用中需要正确关闭 serverSocketChannel 和 selector
}
// handleRead 和 handleWrite 方法省略
}
4. DatagramChannel
DatagramChannel
用于UDP(用户数据报协议)网络通信。UDP是无连接的,所以DatagramChannel
可以向任何IP地址和端口发送数据报,也可以接收来自任何IP地址和端口的数据报。
特点:
- 支持无连接的UDP数据报发送和接收。
- 可以配置为阻塞或非阻塞模式。
- 可以"连接"(
connect
)到一个特定地址,这之后就可以像TCP一样使用read
和write
方法,只与该特定地址通信。
如何获取DatagramChannel
:
DatagramChannel.open()
: 创建一个DatagramChannel
。
常用方法:
bind(SocketAddress local)
: 将通道的套接字绑定到本地地址以接收数据。send(ByteBuffer src, SocketAddress target)
: 向指定目标地址发送数据报。receive(ByteBuffer dst)
: 接收一个数据报,并将数据放入Buffer。返回发送方的地址。在阻塞模式 下,会等待直到收到数据报。在非阻塞模式 下,如果没有数据报会立即返回null
。connect(SocketAddress remote)
: 将通道"连接"到特定的远程地址。连接后,只能向/从此地址发送/接收数据报,并且可以使用read
/write
方法。read(ByteBuffer dst)
: (仅在连接后使用)从连接的对等方读取数据报。write(ByteBuffer src)
: (仅在连接后使用)向连接的对等方发送数据报。disconnect()
: 断开连接(如果已连接)。configureBlocking(boolean block)
: 设置阻塞/非阻塞模式。register(Selector sel, int ops)
: (非阻塞模式)注册到Selector
。
示例:DatagramChannel
发送数据
java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.charset.StandardCharsets;
public class DatagramSender {
public static void main(String[] args) {
String targetHost = "localhost";
int targetPort = 9876;
String message = "UDP Packet from NIO DatagramChannel";
try (DatagramChannel channel = DatagramChannel.open()) {
// 不需要 bind,操作系统会自动分配端口发送
SocketAddress targetAddress = new InetSocketAddress(targetHost, targetPort);
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));
System.out.println("Sending UDP packet to " + targetAddress);
int bytesSent = channel.send(buffer, targetAddress); // 发送数据报
System.out.println("Sent " + bytesSent + " bytes.");
} catch (IOException e) {
System.err.println("Datagram sender error: " + e.getMessage());
e.printStackTrace();
}
}
}
示例:DatagramChannel
接收数据(阻塞模式)
java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.charset.StandardCharsets;
public class DatagramReceiver {
public static void main(String[] args) {
int listenPort = 9876;
try (DatagramChannel channel = DatagramChannel.open()) {
// 绑定到指定端口接收数据
channel.bind(new InetSocketAddress(listenPort));
System.out.println("UDP Receiver started. Listening on port " + listenPort);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (true) { // 循环接收
buffer.clear(); // 准备接收
System.out.println("Waiting to receive UDP packet...");
// 阻塞,直到收到数据报
SocketAddress senderAddress = channel.receive(buffer);
if (senderAddress != null) {
buffer.flip(); // 切换到读模式
byte[] receivedBytes = new byte[buffer.remaining()];
buffer.get(receivedBytes);
String message = new String(receivedBytes, StandardCharsets.UTF_8);
System.out.println("Received " + buffer.limit() + " bytes from " + senderAddress + ": " + message);
// (可选) 可以向发送方回显消息
// String response = "Receiver got: " + message;
// ByteBuffer sendBuffer = ByteBuffer.wrap(response.getBytes(StandardCharsets.UTF_8));
// channel.send(sendBuffer, senderAddress);
}
}
} catch (IOException e) {
System.err.println("Datagram receiver error: " + e.getMessage());
e.printStackTrace();
}
}
}
// 需要先运行 Receiver,再运行 Sender。
总结
Channel
是NIO中数据传输的管道,连接到I/O源(文件、套接字)。Channel
与Buffer
紧密配合,读写操作通过Buffer
进行。FileChannel
用于文件操作,支持随机访问、内存映射和零拷贝。SocketChannel
和ServerSocketChannel
用于TCP网络通信,支持阻塞和非阻塞模式。DatagramChannel
用于UDP网络通信,支持阻塞和非阻塞模式。- 网络相关的
Channel
(SocketChannel
,ServerSocketChannel
,DatagramChannel
)可以配置为非阻塞模式,并与Selector
一起使用,是构建高性能、高并发NIO应用(如Netty框架的基础)的关键。
希望这篇文章的讲解和示例能帮助你理解Java NIO中的Channel
组件!