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);
        }
    }
}


相关文章
|
2月前
|
Java 数据安全/隐私保护
快手小红书抖音留痕工具,自动留痕插件工具,java代码开源
这个框架包含三个核心模块:主操作类处理点赞评论、配置管理类和代理管理类。使用时需要配合
|
1月前
|
算法 IDE Java
Java 项目实战之实际代码实现与测试调试全过程详解
本文详细讲解了Java项目的实战开发流程,涵盖项目创建、代码实现(如计算器与汉诺塔问题)、单元测试(使用JUnit)及调试技巧(如断点调试与异常排查),帮助开发者掌握从编码到测试调试的完整技能,提升Java开发实战能力。
191 0
|
2月前
|
Java 机器人 API
tiktok群控脚本,养号关注私信点赞脚本插件,java代码分享
这个代码模拟了一个社交机器人的基本行为模式,包括登录、关注、点赞、私信等操作。请注意
|
2月前
|
Java 编译器 数据库连接
Java异常处理:写出更健壮的代码
Java异常处理:写出更健壮的代码
145 0
|
4月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
5月前
|
前端开发 Java
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
137 1
|
2月前
|
安全 Java 测试技术
Java 项目实战中现代技术栈下代码实现与测试调试的完整流程
本文介绍基于Java 17和Spring技术栈的现代化项目开发实践。项目采用Gradle构建工具,实现模块化DDD分层架构,结合Spring WebFlux开发响应式API,并应用Record、Sealed Class等新特性。测试策略涵盖JUnit单元测试和Testcontainers集成测试,通过JFR和OpenTelemetry实现性能监控。部署阶段采用Docker容器化和Kubernetes编排,同时展示异步处理和反应式编程的性能优化。整套方案体现了现代Java开发的最佳实践,包括代码实现、测试调试
92 0
|
3月前
|
人工智能 前端开发 Java
Java 面试资料中相关代码使用方法与组件封装方法解析
这是一份详尽的Java面试资料代码指南,涵盖使用方法与组件封装技巧。内容包括环境准备(JDK 8+、Maven/Gradle)、核心类示例(问题管理、学习进度跟踪)、Web应用部署(Spring Boot、前端框架)、单元测试及API封装。通过问题库管理、数据访问组件、学习进度服务和REST接口等模块化设计,帮助开发者高效组织与复用功能,同时支持扩展如用户认证、AI推荐等功能。适用于Java核心技术学习与面试备考,提升编程与设计能力。资源链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
88 6
Java 面试资料中相关代码使用方法与组件封装方法解析
|
2月前
|
SQL Java 数据库连接
Java 期末考试救急必备涵盖绝大多数核心考点及五大类经典代码助你过关
本文为Java期末考试复习指南,涵盖基础语法、面向对象编程、异常处理、文件操作、数据库连接五大核心考点,提供详细解析与实用代码示例,助力快速掌握重点,高效备考,轻松应对考试。
61 0