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 API
探索Java NIO:究竟在哪些领域能大显身手?揭秘原理、应用场景与官方示例代码
Java NIO(New IO)自Java SE 1.4引入,提供比传统IO更高效、灵活的操作,支持非阻塞IO和选择器特性,适用于高并发、高吞吐量场景。NIO的核心概念包括通道(Channel)、缓冲区(Buffer)和选择器(Selector),能实现多路复用和异步操作。其应用场景涵盖网络通信、文件操作、进程间通信及数据库操作等。NIO的优势在于提高并发性和性能,简化编程;但学习成本较高,且与传统IO存在不兼容性。尽管如此,NIO在构建高性能框架如Netty、Mina和Jetty中仍广泛应用。
14 3
|
9天前
|
存储 监控 Java
Java的NIO体系
通过本文的介绍,希望您能够深入理解Java NIO体系的核心组件、工作原理及其在高性能应用中的实际应用,并能够在实际开发中灵活运用这些知识,构建高效的Java应用程序。
26 5
|
1月前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
2月前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
38 2
|
3月前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
4月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
155 0
|
4月前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
94 0
|
5月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
5月前
|
Java
Java中的NIO编程详解
Java中的NIO编程详解
|
5月前
|
Java 大数据
如何在Java中进行网络编程:Socket与NIO
如何在Java中进行网络编程:Socket与NIO