Java NIO 中的 Path 、Files 和 AsychronousFileChannel (附多人聊天室内代码)(下)

简介: Java NIO 中的 Path 、Files 和 AsychronousFileChannel (附多人聊天室内代码)

Java NIO 综合案例


通过 Java NIO 完成一个多人聊天室的案例:


服务端代码:


// 服务端
public class ChatServer {
    // 服务启动
    public void startServer() throws IOException, InterruptedException {
        // 1、创建 Selector 选择器
        Selector selector = Selector.open();
        // 2、创建 ServerSocketChannel 通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 3、为 channel 通道绑定监听端口
        serverSocketChannel.bind(new InetSocketAddress(25000));
        // 设置非阻塞模式
        serverSocketChannel.configureBlocking(false);
        // 4、 把 channel 注册到到 selector 选择器上
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器已经启动成功了");
        // 5、循环,等待新的连接介入
        for (; ; ) {
            // 获取 channel 数量
            int readChannels = selector.select();
            if (readChannels == 0) {
                continue;
            }
            // 获取可用的 channel
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                // 移除 set 集合当前 selectionKey
                iterator.remove();
                // 6、根据就绪状态,调用对应的方法实现具体的操作
                // 6.1 如果 accept 状态
                if (selectionKey.isAcceptable()) {
                    acceptOperator(serverSocketChannel, selector);
                }
                // 6.2 如果可读状态
                else if (selectionKey.isReadable()) {
                    readOperator(selector, selectionKey);
                }
            }
            TimeUnit.SECONDS.sleep(1);
        }
    }
    // 处理可读状态操作
    private void readOperator(Selector selector, SelectionKey selectionKey) throws IOException {
        //1 从 selectionKey 获取已经就绪的通道
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        //2 创建 buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        //3 循环读取客户端发送过来的信息
        int readLen = channel.read(buffer);
        String message = "";
        if (readLen > 0) {
            buffer.flip();
            // 读取内容
            message += Charset.forName("UTF-8").decode(buffer);
        }
        //4 将 channel 再次注册到选择器上,监听可读状态。
        channel.register(selector, SelectionKey.OP_READ);
        //5 把客户端发送的消息,广播到其他的客户端上
        if (message != null && message.length() > 0) {
            // 广播到其他客户端
            System.out.println("message: " + message);
            castOtherClient(message, selector, channel);
        }
    }
    // 广播到其他的客户端
    private void castOtherClient(String message, Selector selector, SocketChannel channel) throws IOException {
        // 1 获取所有已经接入的客户端
        Set<SelectionKey> keys = selector.keys();
        // 2 循环向所有的 channel 广播消息
        for (SelectionKey selectionKey : keys) {
            // 获取里面的每个通道
            SelectableChannel otherChannel = selectionKey.channel();
            // 不需要给自己发送
            if (otherChannel instanceof SocketChannel &&
                channel != otherChannel) {
                ((SocketChannel) otherChannel).write(Charset.forName("UTF-8").encode(message));
            }
        }
    }
    // 处理接入状态操作
    private void acceptOperator(ServerSocketChannel serverSocketChannel, Selector selector) throws IOException {
        // 1 接入状态,状态 创建 socketChannel
        SocketChannel socketChannel = serverSocketChannel.accept();
        // 2 把 socketChannel 设置为非阻塞模式
        socketChannel.configureBlocking(false);
        // 3 把 channel 注册到 selector 选择器上,监听可读状态
        socketChannel.register(selector, SelectionKey.OP_READ);
        // 4 客户端回复信息
        socketChannel.write(Charset.forName("UTF-8").encode("欢迎进入聊天室!"));
    }
    public static void main(String[] args) throws IOException, InterruptedException {
        ChatServer chatServer = new ChatServer();
        chatServer.startServer();
    }
}


客户端代码


// 客户端
// 客户端
public class ChatClient {
    // 启动客户端
    public void startClient(String name) throws IOException {
        // 连接服务器
        SocketChannel socketChannel = SocketChannel.open(
                new InetSocketAddress("127.0.0.1", 25000));
        //接收服务端响应数据
        Selector selector = Selector.open();
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ);
        // 创建线线程
        new Thread(new ClientThread(selector)).start();
        // 向服务器发送消息
        System.out.println("聊天室客户端启动成功!!");
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String msg = scanner.nextLine();
            if (msg != null && msg.length() > 0) {
                socketChannel.write(Charset.forName("UTF-8").encode(name + " : " + msg));
            }
        }
        // 接收服务器的消息
    }
}
// 客户端处理线程
public class ClientThread implements Runnable {
    private Selector selector;
    public ClientThread(Selector selector) {
        this.selector = selector;
    }
    @Override
    public void run() {
        try {
            // 循环,等待新的连接介入
            for (; ; ) {
                // 获取 channel 数量
                int readChannels = 0;
                readChannels = selector.select();
                if (readChannels == 0) {
                    continue;
                }
                // 获取可用的 channel
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    // 移除 set 集合当前 selectionKey
                    iterator.remove();
                    // 根据就绪状态,调用对应的方法实现具体的操作
                    // 如果可读状态
                    if (selectionKey.isReadable()) {
                        readOperator(selector, selectionKey);
                    }
                }
                // TimeUnit.SECONDS.sleep(1);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
    // 处理可读状态操作
    private void readOperator(Selector selector, SelectionKey selectionKey) throws IOException {
        //1 从 selectionKey 获取已经就绪的通道
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        //2 创建 buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        //3 循环读取客户端发送过来的信息
        int readLen = channel.read(buffer);
        String message = "";
        if (readLen > 0) {
            buffer.flip();
            // 读取内容
            message += Charset.forName("UTF-8").decode(buffer);
        }
        //4 将 channel 再次注册到选择器上,监听可读状态。
        channel.register(selector, SelectionKey.OP_READ);
        if (message.length() > 0) {
            // 输出
            System.out.println("收到 message: " + message);
        }
    }
}


相关文章
|
9月前
|
缓存 网络协议 Java
JAVA网络IO之NIO/BIO
本文介绍了Java网络编程的基础与历史演进,重点阐述了IO和Socket的概念。Java的IO分为设备和接口两部分,通过流、字节、字符等方式实现与外部的交互。
292 0
|
11月前
|
监控 Java API
探索Java NIO:究竟在哪些领域能大显身手?揭秘原理、应用场景与官方示例代码
Java NIO(New IO)自Java SE 1.4引入,提供比传统IO更高效、灵活的操作,支持非阻塞IO和选择器特性,适用于高并发、高吞吐量场景。NIO的核心概念包括通道(Channel)、缓冲区(Buffer)和选择器(Selector),能实现多路复用和异步操作。其应用场景涵盖网络通信、文件操作、进程间通信及数据库操作等。NIO的优势在于提高并发性和性能,简化编程;但学习成本较高,且与传统IO存在不兼容性。尽管如此,NIO在构建高性能框架如Netty、Mina和Jetty中仍广泛应用。
310 3
|
11月前
|
存储 监控 Java
Java的NIO体系
通过本文的介绍,希望您能够深入理解Java NIO体系的核心组件、工作原理及其在高性能应用中的实际应用,并能够在实际开发中灵活运用这些知识,构建高效的Java应用程序。
351 5
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
171 2
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
存储 监控 Java
深入探索Java语言的NIO(New I/O)技术
深入探索Java语言的NIO(New I/O)技术
193 1
Java中的NIO编程详解
Java中的NIO编程详解
|
Java 大数据
如何在Java中进行网络编程:Socket与NIO
如何在Java中进行网络编程:Socket与NIO
Java中的NIO编程详解
Java中的NIO编程详解
下一篇
oss云网关配置