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日

相关文章

  • JVM面试和学习中需要注意的部分

    在学习jvm的时候许多人处于迷茫的状态,对一些基础的知识反而听过就忘了,这篇笔记是我在学习jvm的时候随手记的一些,适合已经学过或者了解过的小伙伴复习回顾一下,当然知识的覆盖是没有的,主要记录了我觉得容易忘记或者记错的知识点,这些有很多是基石知识,希望大家不要忘记,大家看到就当正好复习一下,对大家的面试可能会有一点小小的帮助 内存结构 1.方法区用来存储类加…

    Java 2023年5月8日
    00
  • Spring Boot maven框架搭建教程图解

    欢迎来到本站!下面我将为您详细讲解如何使用Maven来创建一个基于Spring Boot的web应用程序。 简介 Spring Boot是一个基于Spring框架的快速开发Web应用程序的工具,它可以帮助开发人员快速构建Web应用程序,同时也提供了各种常用的开发工具和依赖项。 Maven是一款Java构建工具,它可以帮助开发人员管理和构建Java项目中的依赖…

    Java 2023年5月19日
    00
  • Java date format时间格式化操作示例

    当我们在Java中操作日期和时间相关业务时,经常需要进行时间格式化的操作,这时候就需要用到Java的Date和SimpleDateFormat类来进行转化和格式化。下面就是Java date format时间格式化操作示例的完整攻略。 步骤1:导入相关类库 在进行Java时间格式化操作前,需要先导入相关的类库。 import java.util.Date; …

    Java 2023年5月26日
    00
  • 浅谈StringEntity 和 UrlEncodedFormEntity之间的区别

    十分感谢您对本网站的关注,下面是关于 “浅谈StringEntity 和 UrlEncodedFormEntity之间的区别” 的详细讲解。 StringEntity 和 UrlEncodedFormEntity 介绍 StringEntity 和 UrlEncodedFormEntity 是 Apache HttpClient 中两种常见的 HttpEnt…

    Java 2023年5月20日
    00
  • 吃透SpringMVC面试八股文

    说说你对 SpringMVC 的理解 SpringMVC是一种基于 Java 的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于Spring框架的一个模块。 它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful编程风格的请求。 什么是MVC模式? MVC的全名是Model View Control…

    Java 2023年4月20日
    00
  • JS分页的实现(同步与异步)

    JS分页的实现有同步和异步两种方式。在介绍这两种方式之前,需要了解下分页所需的一些数据和参数: 当前页码 currentPage 每页展示数据条数 pageSize 总数据量 totalDataCount 总页数 pageCount 其中,总页数pageCount可根据总数据量totalDataCount和每页展示条数pageSize相除得到。接下来我们分别…

    Java 2023年6月16日
    00
  • java生成指定范围随机数的多种代码

    下面是“java生成指定范围随机数”的完整攻略: 1. 使用java.util.Random类生成随机数 使用java.util.Random类可以生成随机数,这个类提供了一系列的方法来生成数字、布尔值和伪随机字节流。 代码示例1:生成指定范围的随机数 下面是一个例子,生成指定范围内的随机数: import java.util.Random; public …

    Java 2023年5月26日
    00
  • 点击地图div上的按钮实现对地图数据的入库操作

    想要实现在点击地图div上的按钮后能够将地图数据保存到数据库中,需要按照以下步骤进行操作: 在HTML文件中,添加一个按钮到地图的div组件上。可以使用HTML中的button标签,也可以使用一张带有点击事件的图片或图标来代替,将其位置放在地图上层,使得用户能够直接点击按钮实现数据入库功能。 <div id="map" style=…

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