文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java怎么实现NIO聊天室

2023-06-15 01:22

关注

这篇文章给大家分享的是有关Java怎么实现NIO聊天室的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

功能介绍

功能:群聊+私发+上线提醒+下线提醒+查询在线用户

Java怎么实现NIO聊天室

Java怎么实现NIO聊天室

Java怎么实现NIO聊天室

Java怎么实现NIO聊天室

文件

Utils

需要用maven导入下面两个包

 <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>            <version>1.16.18</version>        </dependency>        <dependency>            <groupId>ch.qos.logback</groupId>            <artifactId>logback-classic</artifactId>            <version>1.2.3</version>        </dependency>
package moremorechat_nio;import lombok.extern.slf4j.Slf4j;import java.io.*;@Slf4jpublic class Utils {        public static Message decode(byte[] buf) throws IOException, ClassNotFoundException {        ByteArrayInputStream bais = new ByteArrayInputStream(buf);        ObjectInputStream ois = new ObjectInputStream(bais);        return (Message) ois.readObject();    }        public static byte[] encode(Message message) throws IOException {        ByteArrayOutputStream baos = new ByteArrayOutputStream();        ObjectOutputStream oos = new ObjectOutputStream(baos);        oos.writeObject(message);        oos.flush();        return baos.toByteArray();    }}

FinalValue

package moremorechat_nio;public final class FinalValue {        public static final int MSG_SYSTEM = 0;        public static final int MSG_GROUP = 1;        public static final int MSG_PRIVATE = 2;        public static final int MSG_ONLINE = 3;        public static final int MSG_NAME = 4;}

Message

package moremorechat_nio;import java.io.Serializable;public class Message implements Serializable {    public int type;    public String message;    public Message() {    }    public Message(String message) {        this.message = message;    }    public Message(int type, String message) {        this.type = type;        this.message = message;    }    @Override    public String toString() {        return "Message{" +                "type=" + type +                ", message='" + message + '\'' +                '}';    }}

NioServer

package moremorechat_nio;import lombok.extern.slf4j.Slf4j;import java.io.*;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.*;import java.util.ArrayList;import java.util.Iterator;import java.util.Set;import java.util.concurrent.atomic.AtomicBoolean;import java.util.stream.Collectors;import static moremorechat_nio.FinalValue.*;@Slf4jpublic class NioServer {    private Selector selector;    private ServerSocketChannel ssc;    public NioServer() {        try {            // 创建 selector, 管理多个 channel            selector = Selector.open();            //打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端连接的父通道            ssc = ServerSocketChannel.open();            ssc.bind(new InetSocketAddress(8888));            //设置连接为非堵塞模式            ssc.configureBlocking(false);            // 2. 建立 selector 和 channel 的联系(注册)            // SelectionKey 就是将来事件发生后,通过它可以知道事件和哪个channel的事件            //将ServerSocketChannel注册到Reactor线程的多路复用器Selector上,监听ACCEPT事件            ssc.register(selector, SelectionKey.OP_ACCEPT);        } catch (IOException e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        NioServer server = new NioServer();        log.debug("server启动完成,等待用户连接...");        try {            server.listen();        } catch (Exception e) {            log.debug("发生了一些问题");        }    }        private void listen() throws Exception {        while (true) {            // select 方法, 没有事件发生,线程阻塞,有事件,线程才会恢复运行, 通过Selector的select()方法可以选择已经准备就绪的通道 (这些通道包含你感兴趣的的事件)            //通过Selector的select()方法可以选择已经准备就绪的通道 (这些通道包含你感兴趣的的事件)            // select 在事件未处理时,它不会阻塞, 事件发生后要么处理,要么取消,不能置之不理            selector.select();            // 处理事件, selectedKeys 内部包含了所有发生的事件            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();            while (iterator.hasNext()) {                SelectionKey key = iterator.next();                // 处理key 时,要从 selectedKeys 集合中删除,否则下次处理就会有问题                iterator.remove();                // 区分事件类型                if (key.isAcceptable()) {                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();                    SocketChannel sc = channel.accept();                    sc.configureBlocking(false);                    sc.register(selector, SelectionKey.OP_READ);                } else if (key.isReadable()) {                    dealReadEvent(key);                }            }        }    }        private void dealReadEvent(SelectionKey key) {        SocketChannel channel = null;        try {            channel = (SocketChannel) key.channel();            ByteBuffer buffer = ByteBuffer.allocate(1024);            int read = channel.read(buffer);            // 如果是正常断开,read 的方法的返回值是 -1            if (read == -1) {                //cancel 会取消注册在 selector 上的 channel,并从 keys 集合中删除 key 后续不会再监听事件                key.cancel();            } else {                buffer.flip();                Message msg = Utils.decode(buffer.array());                log.debug(msg.toString());                dealMessage(msg, key, channel);            }        } catch (IOException | ClassNotFoundException e) {            System.out.println((key.attachment() == null ? "匿名用户" : key.attachment()) + " 离线了..");            dealMessage(new Message(MSG_SYSTEM, key.attachment() + " 离线了.."), key, channel);            //取消注册            key.cancel();            //关闭通道            try {                channel.close();            } catch (IOException ioException) {                ioException.printStackTrace();            }        }    }        private void dealMessage(Message msg, SelectionKey key, SocketChannel channel) {        switch (msg.type) {            case MSG_NAME:                key.attach(msg.message);                log.debug("用户{}已上线", msg.message);                getConnectedChannel(channel).forEach(selectionKey -> {                    SocketChannel sc = (SocketChannel) selectionKey.channel();                    sendMsgToClient(new Message("收到一条系统消息: " + msg.message + "已上线"), sc);                });                break;            case MSG_GROUP:                getConnectedChannel(channel).forEach(selectionKey -> {                    SocketChannel sc = (SocketChannel) selectionKey.channel();                    sendMsgToClient(new Message(key.attachment() + "给大家发送了一条消息: " + msg.message), sc);                });                break;            case MSG_PRIVATE:                String[] s = msg.message.split("_");                AtomicBoolean flag = new AtomicBoolean(false);                getConnectedChannel(channel).stream().filter(sk -> s[0].equals(sk.attachment())).forEach(selectionKey -> {                    SocketChannel sc = (SocketChannel) selectionKey.channel();                    sendMsgToClient(new Message(key.attachment() + "给你发送了一条消息: " + s[1]), sc);                    flag.set(true);                });                if (!flag.get()){                    sendMsgToClient(new Message(s[1]+"用户不存在,请重新输入!!!"), channel);                }                break;            case MSG_ONLINE:                ArrayList<String> onlineList = new ArrayList<>();                onlineList.add((String) key.attachment());                getConnectedChannel(channel).forEach(selectionKey -> onlineList.add((String) selectionKey.attachment()));                sendMsgToClient(new Message(onlineList.toString()), channel);                break;            case MSG_SYSTEM:                getConnectedChannel(channel).forEach(selectionKey -> {                    SocketChannel sc = (SocketChannel) selectionKey.channel();                    sendMsgToClient(new Message("收到一条系统消息: " + msg.message), sc);                });                break;            default:                break;        }    }        private void sendMsgToClient(Message msg, SocketChannel sc) {        try {            byte[] bytes = Utils.encode(msg);            sc.write(ByteBuffer.wrap(bytes));        } catch (IOException e) {            log.debug("sendMsgToClient出现了一些问题");        }    }        private Set<SelectionKey> getConnectedChannel(SocketChannel channel) {        return selector.keys().stream()                .filter(item -> item.channel() instanceof SocketChannel && item.channel().isOpen() && item.channel() != channel)                .collect(Collectors.toSet());    }}

NioClient

package moremorechat_nio;import lombok.extern.slf4j.Slf4j;import java.io.*;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Scanner;import static moremorechat_nio.FinalValue.*;@Slf4jpublic class NioClient {    private Selector selector;    private SocketChannel socketChannel;    private String username;    private static Scanner input;    public NioClient() throws IOException {        selector = Selector.open();        socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));        socketChannel.configureBlocking(false);        socketChannel.register(selector, SelectionKey.OP_READ);        log.debug("client启动完成......");        log.debug("请输入你的名字完成注册");        input = new Scanner(System.in);        username = input.next();        log.debug("欢迎{}来到聊天系统", username);    }    public static void main(String[] args) throws IOException {        System.out.println("tips: \n1. 直接发送消息会发给当前的所有用户 \n2. @用户名:消息  会私发给你要发送的用户 \n3. 输入  查询在线用户  会显示当前的在线用户");        NioClient client = new NioClient();        //启动一个子线程接受服务器发送过来的消息        new Thread(() -> {            try {                client.acceptMessageFromServer();            } catch (Exception e) {                e.printStackTrace();            }        }, "receiveClientThread").start();        //调用sendMessageToServer,发送消息到服务端        client.sendMessageToServer();    }        private void sendMessageToServer() throws IOException {        //先把用户名发给客户端        Message message = new Message(MSG_NAME, username);        byte[] bytes = Utils.encode(message);        socketChannel.write(ByteBuffer.wrap(bytes));        while (input.hasNextLine()) {            String msgStr = input.next();            Message msg;            boolean isPrivate = msgStr.startsWith("@");            if (isPrivate) {                int idx = msgStr.indexOf(":");                String targetName = msgStr.substring(1, idx);                msgStr = msgStr.substring(idx + 1);                msg = new Message(MSG_PRIVATE, targetName + "_" + msgStr);            } else if ("查询在线用户".equals(msgStr)) {                msg = new Message(MSG_ONLINE, "请求在线人数");            } else {                msg = new Message(MSG_GROUP, msgStr);            }            byte[] bytes1 = Utils.encode(msg);            socketChannel.write(ByteBuffer.wrap(bytes1));        }    }        private void acceptMessageFromServer() throws Exception {        while (selector.select() > 0) {            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();            while (iterator.hasNext()) {                SelectionKey key = iterator.next();                iterator.remove();                if (key.isReadable()) {                    SocketChannel sc = (SocketChannel) key.channel();                    ByteBuffer buffer = ByteBuffer.allocate(1024);                    sc.read(buffer);                    Message message = Utils.decode(buffer.array());                    log.debug(String.valueOf(message.message));                }            }        }    }}

java基本数据类型有哪些

Java的基本数据类型分为:1、整数类型,用来表示整数的数据类型。2、浮点类型,用来表示小数的数据类型。3、字符类型,字符类型的关键字是“char”。4、布尔类型,是表示逻辑值的基本数据类型。

感谢各位的阅读!关于“Java怎么实现NIO聊天室”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯