通道Channel案例

wen java案例 7

本文目录导读:

通道Channel案例

  1. FileChannel 基础案例
  2. SocketChannel 客户端案例
  3. ServerSocketChannel 服务端案例
  4. 非阻塞模式案例
  5. DatagramChannel 案例(UDP)

我来为你展示一个完整的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的主要特点:

  1. 双向通信:大多数Channel支持读写双向操作(FileChannel除外)
  2. 非阻塞模式:支持非阻塞I/O操作
  3. 直接缓冲区:可以与ByteBuffer配合使用,提高性能
  4. 传输效率高:支持transferTo/transferFrom进行高效数据传输

使用场景:

  • FileChannel:文件读写、复制
  • SocketChannel:TCP客户端
  • ServerSocketChannel:TCP服务端
  • DatagramChannel:UDP通信
  • 与Selector配合:实现高并发非阻塞网络编程

抱歉,评论功能暂时关闭!