用netty实现聊天

news2024/11/24 12:00:50

1.引入netty依赖

<dependencies>
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.92.Final</version>
</dependency>
</dependencies>

2.准备一个服务端ChatServer和一个服务端处理器ChatServerHandler和若干个客户端ChatClient(有几个用户设置几个)和一个客户端处理器ChatClientHandler

服务端
public class ChatServer {
    public static void main(String[] args) {
        // 新建两个事件循环组,bossGroup 用于监听客户端的连接请求,将连接请求发送给 workerGroup 用于处理客户端连接的数据读写
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workGroup);
        serverBootstrap.channel(NioServerSocketChannel.class);
        serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel ch) throws Exception {
                ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
                ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
                ch.pipeline().addLast(new ChatServerHandler());
            }
        });
        // 服务端绑定9000端口
        serverBootstrap.bind(9000);
    }

    public void test(){
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup,workGroup);

        serverBootstrap.channel(NioServerSocketChannel.class);
        serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                nioSocketChannel.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
                nioSocketChannel.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
                nioSocketChannel.pipeline().addLast(new ChatServerHandler());
            }
        });

        serverBootstrap.bind(9001);
    }
}

服务端处理器

public class ChatServerHandler extends ChannelInboundHandlerAdapter {

    // 创建一个list集合存储连接上的所有客户端channel
    private static List<Channel> channels = new ArrayList<>();

    // 当有客户端连接上服务端,底层会调用此方法,执行此方法的逻辑
    // 这里大概的处理逻辑是:先添加新客户端channel到集合中,然后循环遍历list集合
    // 然后根据不同的channel发送不同的系统消息
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channels.add(channel);
        channels.forEach(ch -> {
            if (ch == channel) {
                channel.writeAndFlush("恭喜您,上线成功");
            } else {
                ch.writeAndFlush("系统消息:[" + ch.remoteAddress() + "]客户端已上线");
            }
        });
        System.out.println("客户端[" + channel.remoteAddress() + "]请求连接");
    }

    // 当有客户端连断开连接,底层会调用此方法,执行此方法的逻辑
    // 这里大概的处理逻辑是:然后循环遍历list集合,找到已断开连接的channel并删除
    // 向集合内的channel发送系统消息
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        Iterator<Channel> iterator = channels.iterator();
        while (iterator.hasNext()) {
            Channel ch = iterator.next();
            if (ch == channel) {
                iterator.remove();
            }
            ch.writeAndFlush("系统消息:[" + channel.remoteAddress() + "]客户端已下线");
        }
        System.out.println("客户端[" + channel.remoteAddress() + "]断开连接");
    }

    // 当有客户端发送消息到服务端,底层会调用此方法,执行此方法的逻辑
    // 这里大概的处理逻辑是:循环遍历向集合中的channel(除发送消息的客户端)发送消息
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel channel = ctx.channel();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(System.currentTimeMillis());
        String now = formatter.format(date);
        System.out.println(now+"收到用户[" + channel.remoteAddress() + "]发来的消息:" + msg.toString());

        channels.forEach(ch -> {
            if (ch != channel) {
                ch.writeAndFlush("消息时间:" + now + " 用户[" + channel.remoteAddress() + "]说:" + msg.toString());
            }
        });
    }


    //异常触发
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

客户端

public class ChatClient {
    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup workGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(workGroup);
        bootstrap.channel(NioSocketChannel.class);
        // 设置处理器
        bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel ch) throws Exception {
                // 将字符串编解码器及客户端处理器添加到pipeline中
                ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
                ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
                ch.pipeline().addLast(new ChatClientHandler());
            }
        });
        // 连接服务端
        ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9000);
        channelFuture.sync();
        // 获取客户端输入的内容,并发送至服务端(因为添加了字符串编解码器,所以此处可以直接发送字符串)
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            channelFuture.channel().writeAndFlush(scanner.nextLine());
        }
    }
}

客户端处理器

public class ChatClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println(msg.toString());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

如果需要多个客户端用户,将客户端多复制几个就可以了.

启动时先启动服务端再启动客户端

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/535169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis优化与常见问题

---------------------- Redis 命令工具 ---------------------------------------- redis-server&#xff1a;用于启动 Redis 的工具 redis-benchmark&#xff1a;用于检测 Redis 在本机的运行效率 redis-check-aof&#xff1a;修复 AOF 持久化文件 redis-check-rdb&#xff1…

C语言库函数详解(两万字)

目录 目录 目录 前言 1.C 标准库 - <stdio.h> 简介 1.1 printf&#xff08;&#xff09;&#xff1b; 1.2 scanf(); 1.3 getchar(); 1.4 putchar(); 1.5 gets(); 1.6 puts(); 1.7fscanf(); 1.8 fprintf(); 1.9 fgetc(); 1.10 fgets(); 1.11 fputs(); 1.12 fclose();…

人机融合智能中的诱导引导交互

智能的核心不在于人工智能系统的记忆、注意力和上下文感知等能力&#xff0c;而在于其能够洞察、理解和解决问题的能力。也就是说智能系统需要具备更高层次的思维能力&#xff0c;能够从信息中抽象出本质&#xff0c;识别问题的核心&#xff0c;并提供有效的解决方案。这对于人…

MATLAB绘制动画(四)AVI

MATLAB绘制动画&#xff08;四&#xff09;AVI与GIF clc; clear; close all; fig figure ; aviobj avifile(example.avi); n 100; t 0:2*pi/n:2*pi; x cos(t); y sin(t); for k 1:nx(k) cos(t(k));y(k) sin(t(k));H plot(x,y,x(k),y(k),or,x(k),-y(k),ob);axis equa…

应届生怎么才能提高职场竞争力

前言 随着社会的不断发展&#xff0c;竞争也在逐渐增加。对于应届生来说&#xff0c;提高职场竞争力是很重要的&#xff0c;这样才能更好地融入工作环境、获得更好的机会和待遇。那么&#xff0c;应届生怎么才能提高职场竞争力呢&#xff1f;本文就来简单聊一聊。 应届生步入职…

【再获殊荣】中创算力入选“河南省2023年第五批拟入库科技型中小企业名单”

科技促发展&#xff0c;创新赢未来&#xff01; 科技型中小企业作为最具活力、最具潜力、最具成长性的创新群体&#xff0c;已成为我国在经济转型阶段培育发展新动能的重要载体&#xff01; 2022年&#xff0c;中创算力正式入库河南省2022年科技型中小企业。 2023年&#xf…

F. Array Stabilization (GCD version)

题目链接&#xff1a;传送门 思路&#xff1a; 进行预处理的算法模板&#xff1a; for(int i1;(1<<i)<n;i)for(int j1;j(1<<i)-1<n;j)st[j][i]gcd(st[j][i-1],st[j(1<<(i-1))][i-1]);进行查询的算法模板 int check(int i,int mid){int klog2(mid-i1);…

【Mybatis】Mybatis的动态SQL、缓存机制-三

唠嗑部分 之前我们说了Mybatis的基本操作、关系映射等等&#xff0c;相关文章&#xff1a; 【Mybatis】简单入门及工具类封装-一 【Mybatis】如何实现ORM映射-二 本篇文章和大家说的是Mybatis的动态SQL、缓存机制 言归正传 一、动态SQL MyBatis的映射文件中支持在基础SQL上…

系统分析师:六、企业信息化战略与实施

目录 一、信息与信息化概念 1.1 信息的概念 1.2 信息化的概念 二、信息系统 2.1 信息系统的概念 2.2 信息系统的类型 2.3 信息系统的生命周期 2.4 系统建模 2.5 信息系统战略规划 2.6 信息化开发方法 三、电子政务 四、企业资源计划(ERP) 五、系统集成 一、信息与信息…

k8s1.20版本部署Redis集群(三主三从)——2023.05

文章目录 一、准备工作二、逻辑图三、部署Redis集群1. 安装NFS服务2. 修改API配置3. 创建持久卷PVC4. 创建Redis服务4. 组建Redis集群5. 验证集群 一、准备工作 主机规划 节点IPk8s-master1192.168.2.245k8s-master2192.168.2.246k8s-master3192.168.2.247k8s-node1192.168.2…

【MySQL】-- 库的操作

目录 库的操作 显示数据库 创建数据库 创建数据库案例 删除数据库 删除数据库案例 字符集和校验规则 字符集 校验规则 小结 查看数据库支持的字符集 查看数据库支持的校验规则 校验规则对数据库的影响 不区分大小写 区分大小写 进行查询 结果排序 修改数据库…

我爱我家联合第四范式发布房产经纪大模型

5月15日&#xff0c;在我爱我家年度品牌战略发布会上&#xff0c;我爱我家联合第四范式发布“房产经纪大模型”&#xff0c;将大模型能力用于提升行业生产力的原点&#xff1a;赋能经纪人。本次发布的房产经纪大模型1.0版本已经具备了合格经纪人的基本能力&#xff0c;‍‍‍‍…

leetcode 不同路径详解

文章目录 62 . 不同路径题目详情动态规划之带备忘录实现Java完整代码 63. 不同路径 II题目详情动态规划之带备忘录实现Java完整代码 62 . 不同路径 题目详情 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只…

JavaSE进阶(二)—— 面向对象进阶(包、权限修饰符、抽象类、多态)

目录 一、包 1. 什么是包 2. 导包 二、权限修饰符 1. 什么是权限修饰符 2. 权限修饰符的分类和具体作用范围 3. 学完权限修饰符需要具备如下能力 三、final 1. final的作用 2. final修饰变量的注意 四、常量 1. 常量概述和基本作用 1.1 常量做信息配置的原理、优…

【操作系统】I/O管理

文章目录 I/O设备的基本概念和分类I/O设备的分类 I/O控制器I/O设备的组成I/O控制器的组成I/O控制器的两种寄存器编址方式 I/O控制方式程序直接控制方式中断驱动方式DMA方式通道控制方式 I/O软件的层次结构用户层软件设备独立性软件六大功能逻辑设备表—LUT 设备驱动程序中断处理…

免交互的使用

免交互的使用 一、免交互二、小实验三、利用脚本完成的小实验三、Expect 一、免交互 Here Document 免交互 使用I/O重定向的方式将命令列表提供给交互式程序或命令&#xff0c;比如ftp、cat或者read命令。 免交互时标准输入的一种替代品可以帮助脚本开发人员不必使用临时文件来…

MySQL查询练习题

一&#xff0e;编程题 有三张表&#xff0c;结构如下&#xff1a; Student(学号StuId,姓名StuName,性别StuSex,出生年月StuBirth) Course(课程号CouId,课程名CouName,授课教师CoouTeacher) SC(学号StuId,课程号CouId,成绩Score,授课教师CouTeacher) 用标准SQL语句完成下列操作…

第六章 介绍Productions - 其他Production 选项

文章目录 第六章 介绍Productions - 其他Production 选项用户门户工作流业务活动监控Alerts发布和订阅消息传递Message Bank 第六章 介绍Productions - 其他Production 选项 本章概述了与制作相关的其他选项。 用户门户 与 Studio 和管理门户等后端工具不同&#xff0c;用户…

免交互 (Here Document)

目录 免交互 (Here Document) 语法格式&#xff1a; 注意事项&#xff1a; 支持变量替换 多行注释 Expect 基本命令: interact 嵌入执行模式 实现 ssh 自动登录 免交互 (Here Document) 使用I/O重定向的方式将命令列表提供给交互式程序或命令&#xff0c;比如 ftp、c…

阿里云异构计算云服务器GPU、FPGA和EAIS详解

阿里云阿里云异构计算主要包括GPU云服务器、FPGA云服务器和弹性加速计算实例EAIS&#xff0c;随着人工智能技术的发展&#xff0c;越来越多的AI计算都采用异构计算来实现性能加速&#xff0c;阿里云异构计算云服务研发了云端AI加速器&#xff0c;通过统一的框架同时支持了Tenso…