本文目录导读:

我来为你展示一个完整的Java NIO Channel案例,包含常见的FileChannel、SocketChannel和ServerSocketChannel的使用。
FileChannel 基础案例
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class FileChannelExample {
// 写入文件
public static void writeToFile(String content, String filePath) throws IOException {
try (FileChannel channel = new FileOutputStream(filePath).getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(content.getBytes());
buffer.flip(); // 切换为读模式
while (buffer.hasRemaining()) {
channel.write(buffer);
}
System.out.println("文件写入完成!");
}
}
// 读取文件
public static String readFromFile(String filePath) throws IOException {
StringBuilder result = new StringBuilder();
try (FileChannel channel = new FileInputStream(filePath).getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (channel.read(buffer) != -1) {
buffer.flip(); // 切换为读模式
while (buffer.hasRemaining()) {
result.append((char) buffer.get());
}
buffer.clear(); // 清空缓冲区,准备下一次读取
}
}
return result.toString();
}
// 文件复制
public static void copyFile(String sourcePath, String destPath) throws IOException {
try (FileChannel sourceChannel = new FileInputStream(sourcePath).getChannel();
FileChannel destChannel = new FileOutputStream(destPath).getChannel()) {
// 使用 transferTo 方法复制
long size = sourceChannel.size();
sourceChannel.transferTo(0, size, destChannel);
// 或者使用 transferFrom
// destChannel.transferFrom(sourceChannel, 0, size);
System.out.println("文件复制完成,大小:" + size + " bytes");
}
}
public static void main(String[] args) throws IOException {
// 测试写入
writeToFile("Hello NIO Channel!", "test.txt");
// 测试读取
String content = readFromFile("test.txt");
System.out.println("读取的内容:" + content);
// 测试复制
copyFile("test.txt", "test_copy.txt");
}
}
SocketChannel 客户端案例
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
public class SocketChannelClient {
private SocketChannel socketChannel;
private ByteBuffer buffer;
public void connect(String host, int port) throws IOException {
// 创建 SocketChannel 并连接服务器
socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress(host, port));
buffer = ByteBuffer.allocate(1024);
System.out.println("已连接到服务器: " + host + ":" + port);
}
public void sendMessage(String message) throws IOException {
// 清空缓冲区并写入消息
buffer.clear();
buffer.put(message.getBytes(StandardCharsets.UTF_8));
buffer.flip();
// 发送消息
while (buffer.hasRemaining()) {
socketChannel.write(buffer);
}
System.out.println("消息发送成功: " + message);
}
public String receiveMessage() throws IOException {
buffer.clear();
int bytesRead = socketChannel.read(buffer);
if (bytesRead == -1) {
return null; // 连接已关闭
}
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
return new String(bytes, StandardCharsets.UTF_8);
}
public void close() throws IOException {
if (socketChannel != null) {
socketChannel.close();
}
}
public static void main(String[] args) {
SocketChannelClient client = new SocketChannelClient();
try {
client.connect("localhost", 8888);
// 发送多条消息
client.sendMessage("Hello Server!");
client.sendMessage("This is client message");
// 接收服务器响应
String response = client.receiveMessage();
if (response != null) {
System.out.println("收到服务器响应: " + response);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
ServerSocketChannel 服务端案例
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;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ServerSocketChannelExample {
private ServerSocketChannel serverSocketChannel;
private ExecutorService threadPool;
private ByteBuffer buffer;
public void start(int port) throws IOException {
// 创建 ServerSocketChannel
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(true); // 使用阻塞模式
buffer = ByteBuffer.allocate(1024);
threadPool = Executors.newFixedThreadPool(4);
System.out.println("服务器启动,监听端口: " + port);
while (true) {
try {
// 接受客户端连接
SocketChannel clientChannel = serverSocketChannel.accept();
System.out.println("收到客户端连接: " + clientChannel.getRemoteAddress());
// 为每个客户端创建独立线程处理
threadPool.submit(() -> handleClient(clientChannel));
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void handleClient(SocketChannel clientChannel) {
try {
// 处理客户端消息
while (true) {
int bytesRead = clientChannel.read(buffer);
if (bytesRead == -1) {
System.out.println("客户端断开连接");
break;
}
if (bytesRead > 0) {
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String message = new String(bytes, StandardCharsets.UTF_8);
System.out.println("收到客户端消息: " + message);
// 响应客户端
String response = "Server received: " + message;
buffer.clear();
buffer.put(response.getBytes());
buffer.flip();
while (buffer.hasRemaining()) {
clientChannel.write(buffer);
}
}
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void shutdown() throws IOException {
threadPool.shutdown();
if (serverSocketChannel != null) {
serverSocketChannel.close();
}
}
public static void main(String[] args) {
ServerSocketChannelExample server = new ServerSocketChannelExample();
try {
server.start(8888);
} catch (IOException e) {
e.printStackTrace();
}
}
}
非阻塞模式案例
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
public class NonBlockingServer {
private Selector selector;
private ServerSocketChannel serverSocketChannel;
public void start(int port) throws IOException {
// 创建 Selector
selector = Selector.open();
// 配置非阻塞ServerSocketChannel
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);
// 注册 ACCEPT 事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("非阻塞服务器启动,监听端口: " + port);
// 事件循环
while (true) {
selector.select(); // 阻塞等待事件发生
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove(); // 手动移除,防止重复处理
try {
if (key.isAcceptable()) {
handleAccept(key);
} else if (key.isReadable()) {
handleRead(key);
}
} catch (IOException e) {
key.cancel();
key.channel().close();
e.printStackTrace();
}
}
}
}
private void handleAccept(SelectionKey key) throws IOException {
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = serverChannel.accept();
if (clientChannel != null) {
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("接受新连接: " + clientChannel.getRemoteAddress());
}
}
private void handleRead(SelectionKey key) throws IOException {
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = clientChannel.read(buffer);
if (bytesRead == -1) {
System.out.println("客户端关闭连接: " + clientChannel.getRemoteAddress());
clientChannel.close();
return;
}
if (bytesRead > 0) {
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String message = new String(bytes);
System.out.println("收到消息: " + message);
// 回显消息
ByteBuffer writeBuffer = ByteBuffer.wrap(("Echo: " + message).getBytes());
clientChannel.write(writeBuffer);
}
}
public static void main(String[] args) {
NonBlockingServer server = new NonBlockingServer();
try {
server.start(9999);
} catch (IOException e) {
e.printStackTrace();
}
}
}
DatagramChannel 案例(UDP)
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.charset.StandardCharsets;
public class DatagramChannelExample {
// UDP 服务器
public static class UDPServer {
public void start(int port) throws IOException {
DatagramChannel channel = DatagramChannel.open();
channel.bind(new InetSocketAddress(port));
channel.configureBlocking(true);
ByteBuffer buffer = ByteBuffer.allocate(1024);
System.out.println("UDP服务器启动,监听端口: " + port);
while (true) {
buffer.clear();
InetSocketAddress client = (InetSocketAddress) channel.receive(buffer);
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String message = new String(bytes, StandardCharsets.UTF_8);
System.out.println("收到客户端消息: " + message);
// 发送响应
String response = "Server response: " + message;
channel.send(ByteBuffer.wrap(response.getBytes()), client);
}
}
}
// UDP 客户端
public static class UDPClient {
public void sendAndReceive(String message, String host, int port) throws IOException {
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(true);
// 发送数据
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
channel.send(buffer, new InetSocketAddress(host, port));
System.out.println("发送消息: " + message);
// 接收响应
ByteBuffer responseBuffer = ByteBuffer.allocate(1024);
InetSocketAddress server = (InetSocketAddress) channel.receive(responseBuffer);
responseBuffer.flip();
byte[] bytes = new byte[responseBuffer.remaining()];
responseBuffer.get(bytes);
System.out.println("收到服务器响应: " + new String(bytes));
channel.close();
}
}
public static void main(String[] args) throws IOException {
// 启动服务器线程
new Thread(() -> {
try {
new UDPServer().start(7777);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
// 等待服务器启动
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 客户端发送消息
new UDPClient().sendAndReceive("Hello UDP Server!", "localhost", 7777);
}
}
Channel的主要特点:
- 双向通信:大多数Channel支持读写双向操作(FileChannel除外)
- 非阻塞模式:支持非阻塞I/O操作
- 直接缓冲区:可以与ByteBuffer配合使用,提高性能
- 传输效率高:支持transferTo/transferFrom进行高效数据传输
使用场景:
- FileChannel:文件读写、复制
- SocketChannel:TCP客户端
- ServerSocketChannel:TCP服务端
- DatagramChannel:UDP通信
- 与Selector配合:实现高并发非阻塞网络编程