Java NIO实现群聊系统

Java NIO实现群聊系统攻略

1. 概述

Java NIO(New I/O)是Java 1.4版本引入的新的I/O模型,与之前的I/O模型(阻塞式I/O)不同,Java NIO使用了非阻塞I/O模型。在Java NIO中,所有的I/O操作都是异步的,即非阻塞的。

Java NIO实现群聊系统,可以使用Java NIO的SocketChannel和Selector两个关键类来实现。本文将重点介绍如何使用Java NIO创建一个简单的群聊系统,实现服务端和客户端之间的通信。

2. 群聊系统实现流程

Java NIO实现群聊系统的流程如下:

  1. 创建服务端:
    • 创建一个ServerSocketChannel对象,绑定指定的端口,并设置为非阻塞模式
    • 创建一个Selector对象,将ServerSocketChannel注册到Selector中,监听OP_ACCEPT事件
    • 使用Selector进行I/O操作,处理客户端的请求
  2. 创建客户端:
    • 创建一个SocketChannel对象,连接到指定的服务端,并设置为非阻塞模式
    • 将SocketChannel注册到Selector中,监听OP_READ事件
    • 使用Selector进行I/O操作,与服务端进行通信
  3. 处理请求:
    • 服务端监听到有客户端连接请求时,通过ServerSocketChannel.accept()方法获取连接的SocketChannel对象
    • 将该SocketChannel对象注册到Selector中,监听OP_READ事件
    • 客户端向服务器发送消息时,服务端使用SocketChannel.read()方法读取消息
    • 服务端将收到的消息广播给所有连接的客户端
  4. 广播消息:
    • 客户端向服务器发送消息时,使用SocketChannel.write()方法将消息发送给服务端
    • 服务端收到消息后,将消息发送给所有连接的客户端

3. 示例说明

示例1:服务端

public class Server {
    public static void main(String[] args) throws IOException {
        // 创建ServerSocketChannel对象
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 绑定服务端口
        serverSocketChannel.socket().bind(new InetSocketAddress("localhost", 6666));
        // 设置为非阻塞模式
        serverSocketChannel.configureBlocking(false);
        // 创建Selector对象
        Selector selector = Selector.open();
        // 将ServerSocketChannel注册到Selector中,监听OP_ACCEPT事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            // 使用Selector进行I/O操作
            selector.select();
            // 获取所有已经就绪的SelectionKey
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> it = selectionKeys.iterator();
            while (it.hasNext()) {
                SelectionKey selectionKey = it.next();
                if (selectionKey.isAcceptable()) {
                    // 有新的客户端连接请求
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    // 将该SocketChannel注册到Selector中,监听OP_READ事件
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("[Server] " + socketChannel.getRemoteAddress() + " 上线了");
                } else if (selectionKey.isReadable()) {
                    // 处理客户端发来的消息
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int len = 0;
                    while ((len = socketChannel.read(buffer)) > 0) {
                        buffer.flip();
                        String message = new String(buffer.array(), 0, len);
                        System.out.println("[Server] " + socketChannel.getRemoteAddress() + " : " + message);
                        // 广播消息
                        broadcast(selector, message, socketChannel);
                    }
                }
                // 从集合中删除已经处理的SelectionKey
                it.remove();
            }
        }
    }

    // 广播消息给所有连接的客户端
    private static void broadcast(Selector selector, String message, SocketChannel self) throws IOException {
        Set<SelectionKey> selectionKeys = selector.keys();
        for (SelectionKey selectionKey : selectionKeys) {
            Channel channel = selectionKey.channel();
            if (channel instanceof SocketChannel && channel != self) {
                SocketChannel socketChannel = (SocketChannel) channel;
                ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
                socketChannel.write(buffer);
            }
        }
    }
}

示例2:客户端

public class Client {
    public static void main(String[] args) throws IOException {
        // 创建SocketChannel对象
        SocketChannel socketChannel = SocketChannel.open();
        // 连接服务端
        socketChannel.connect(new InetSocketAddress("localhost", 6666));
        // 设置为非阻塞模式
        socketChannel.configureBlocking(false);
        // 创建Selector对象
        Selector selector = Selector.open();
        // 将SocketChannel注册到Selector中,监听OP_READ事件
        socketChannel.register(selector, SelectionKey.OP_READ);

        // 发送消息给服务端
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String message = scanner.nextLine();
            ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
            socketChannel.write(buffer);
        }
    }
}

以上示例演示了如何使用Java NIO实现群聊系统,运行示例1服务端和多个示例2客户端,可以通过控制台输入信息实现多个客户端之间的群聊。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java NIO实现群聊系统 - Python技术站

(0)
上一篇 2023年5月30日
下一篇 2023年5月30日

相关文章

  • JSP 中response.setContentType()的作用及参数

    在 JSP 程序中,response.setContentType() 方法可以设置响应的MIME类型,MIME 类型全称是 Multipurpose Internet Mail Extensions,意为多用途互联网邮件扩展类型,它是一种标准,用来表示文档在网络传输中的格式,例如 HTML 页面可以使用 text/html,JPG 图片可以使用 image…

    Java 2023年6月15日
    00
  • Spring Bean的8种加载方式总结

    Spring Bean的8种加载方式总结 在Spring框架中,Bean是我们经常使用的核心概念之一。Spring提供了多种Bean加载方式,以适应不同的场景和需求。本文将对Spring Bean的8种加载方式进行详细讲解,并通过示例说明。 1. 通过XML文件加载Bean 最传统的方式是使用XML文件来定义Bean。我们可以在XML中使用<bean&…

    Java 2023年5月31日
    00
  • SpringBoot监控Tomcat活动线程数来判断是否完成请求处理方式

    要实现Spring Boot监控Tomcat线程数并判断是否请求处理完成可以采用以下步骤: 1. 添加actuator依赖 要使用Spring Boot提供的监控功能,需要添加actuator依赖,具体方法是在项目的pom.xml文件中添加以下代码: <dependency> <groupId>org.springframework.…

    Java 2023年5月19日
    00
  • Jsp中request的3个基础实践

    JSP中的request对象是Web开发的一个重要组成部分,它用于在不同的Web组件之间传递数据。下面是request对象在JSP中的3个基础实践的完整攻略: 1. 在JSP页面中获取request对象 在许多情况下,我们需要在JSP页面中获取request对象。要实现这一点,我们可以使用Java中的“内置对象”- request。request作为内置对象…

    Java 2023年6月15日
    00
  • Spring Security权限想要细化到按钮实现示例

    为了实现Spring Security权限细化到按钮级别的权限控制,需要经过以下几个步骤: 步骤1,配置Spring Security 在Spring Security的配置中添加按钮级别的权限控制。 @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSec…

    Java 2023年5月20日
    00
  • Java字节码操纵库的作用是什么?

    Java字节码操纵库是指一些Java类库,它们在Java字节码层次上操作Java类的定义和结构。这种操纵方式不涉及源代码,适用于各种Java开发和工具套件。Java字节码操纵库不仅可以读取Java类文件的字节码,而且还可以根据需要修改类的数据和结构信息。Java字节码操纵库的主要用途是生成字节码、动态修改字节码以及分析字节码等。下面将介绍如何使用Java字节…

    Java 2023年5月11日
    00
  • 什么是类卸载?

    类卸载是Java虚拟机(JVM)中的一项重要功能,它可以卸载运行时的类。在Java应用程序中,当一个类没有被引用时,JVM会自动释放该类所占用的内存。这个过程称为“类卸载”。 类卸载的实现是通过垃圾收集器完成的。在JVM中,垃圾收集器会判断一个类是否完全没有被引用,如果没有引用,则该类不再被使用。当该类不再被使用时,JVM会卸载该类,释放其内存,并将该类从方…

    Java 2023年5月11日
    00
  • Java中难理解的四个概念

    下面是讲解Java中难理解的四个概念的攻略。 1. 非静态内部类和静态内部类 对于Java中的内部类,可以分为两种类型:非静态内部类和静态内部类。 非静态内部类的创建需要依赖于外部类的实例,而静态内部类则不需要。简单来说,非静态内部类可以访问外部类的非静态成员和方法,而且可以直接访问外部类的实例变量。静态内部类则不能直接访问外部类的实例变量和非静态成员,但可…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部