netty之NettyServer群发消息

news2024/10/2 13:43:15

前言


在微信或者QQ的聊天中我们经常会用到一些群聊,把你的信息发送给所有用户。那么为了实现群发消息,在netty中我们可以使用ChannelGroup方式进行群发消息。如果为了扩展验证比如你实际聊天有不同的群,那么可以定义ConcurrentHashMap结构来存放ChannelGroup。ChannelGroup中提供了一些基础的方法;添加、异常、查找、清空、发放消息、关闭等。
在这里插入图片描述
新建ChannelHandler


public class ChannelHandler {
    //用于存放用户Channel信息,也可以建立map结构模拟不同的消息群
    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

}


public class MyChannelInitializer  extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel channel) {
        // 基于换行符号
        channel.pipeline().addLast(new LineBasedFrameDecoder(1024));
        // 解码转String,注意调整自己的编码格式GBK、UTF-8
        channel.pipeline().addLast(new StringDecoder(Charset.forName("GBK")));
        // 解码转String,注意调整自己的编码格式GBK、UTF-8
        channel.pipeline().addLast(new StringEncoder(Charset.forName("GBK")));
        // 在管道中添加我们自己的接收数据实现方法
        channel.pipeline().addLast(new MyServerHandler());
    }
}

public class MyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //当有客户端链接后,添加到channelGroup通信组
        ChannelHandler.channelGroup.add(ctx.channel());
        //日志信息
        SocketChannel channel = (SocketChannel) ctx.channel();
        System.out.println("链接报告开始");
        System.out.println("链接报告信息:有一客户端链接到本服务端");
        System.out.println("链接报告IP:" + channel.localAddress().getHostString());
        System.out.println("链接报告Port:" + channel.localAddress().getPort());
        System.out.println("链接报告完毕");
        //通知客户端链接建立成功
        String str = "通知客户端链接建立成功" + " " + new Date() + " " + channel.localAddress().getHostString() + "\r\n";
        ctx.writeAndFlush(str);
    }

    /**
     * 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端断开链接" + ctx.channel().localAddress().toString());
        // 当有客户端退出后,从channelGroup中移除。
        ChannelHandler.channelGroup.remove(ctx.channel());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //接收msg消息{与上一章节相比,此处已经不需要自己进行解码}
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);
        //收到消息后,群发给客户端
        String str = "服务端收到:" + new Date() + " " + msg + "\r\n";
        ChannelHandler.channelGroup.writeAndFlush(str);
    }

    /**
     * 抓住异常,当发生异常的时候,可以做一些相应的处理,比如打印日志、关闭链接
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        System.out.println("异常信息:\r\n" + cause.getMessage());
    }

}
public class NettyServer {
    public static void main(String[] args) {
        new NettyServer().bing(7397);
    }

    private void bing(int port) {
        //配置服务端NIO线程组
        EventLoopGroup parentGroup = new NioEventLoopGroup(); //NioEventLoopGroup extends MultithreadEventLoopGroup Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
        EventLoopGroup childGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(parentGroup, childGroup)
                    .channel(NioServerSocketChannel.class)    //非阻塞模式
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childHandler(new MyChannelInitializer());
            ChannelFuture f = b.bind(port).sync();
            System.out.println("server start done. {关注明哥,获取源码}");
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            childGroup.shutdownGracefully();
            parentGroup.shutdownGracefully();
        }

    }
}

启动nettyServer服务端进行测试
在这里插入图片描述
启动两个客服端即可

好了到这里就结束了基础nnetty之NettyServer群发消息的学习,大家一定要跟着动手操作起来。需要的源码的 可si我获取;

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

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

相关文章

程计软考题2-编译、解释程序翻译阶段

(一) 编译器和解释器的工作阶段 1.编译和解释与源程序的区别 分析&#xff1a;编译和解释是语言处理的两种基本方式。 编译过程包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等阶段&#xff0c;以及符号表管理和出错处理模块。 解释过程在词法、语…

Nuxt.js 应用中的 app:rendered 钩子详解

title: Nuxt.js 应用中的 app:rendered 钩子详解 date: 2024/10/2 updated: 2024/10/2 author: cmdragon excerpt: 摘要:本文详细介绍了 Nuxt.js 应用程序中的 app:rendered 钩子,包括其定义、调用时机、上下文信息以及通过实际案例展示如何记录性能和发送日志到服务器。 …

基于大数据的大屏高速公路收费系统的开发设计与实现SpringBoot+vue

目录 1. 需求分析 2. 技术选型 3. 系统架构设计 4. 开发实现 5. 代码示例和效果演示 6. 持续优化 由于我国高速公路的建设和发展与国外先进国家有很大差距。在高速公路建成后&#xff0c;收费系统往往选用国外的成熟产品。虽然这些产品在功能上基本满足了高速公路收费的要…

如何用JavaScript编写一个简单的计数器

在网页开发中&#xff0c;计数器是一种常见的功能&#xff0c;它可以帮助我们记录点击次数、显示时间等。下面我将介绍如何在HTML页面中使用JavaScript实现一个基本的计数器。如图&#xff1a; 1、 创建HTML结构 首先&#xff0c;我们需要创建一个基础的HTML结构来容纳我们的计…

影视cms泛目录用什么程序?苹果cms二次开发泛目录插件

影视CMS泛目录一般使用的程序有很多种&#xff0c;&#xff08;maccmscn&#xff09;以下是其中几种常见的程序&#xff1a; WordPress&#xff1a;WordPress是一个非常流行的开源内容管理系统&#xff0c;可以通过安装一些插件来实现影视CMS泛目录功能。其中&#xff0c;一款常…

matlab初学习记录

文章目录 内置函数与变量matlab 编辑器数组等间距向量数组函数数组索引提取多个元素 对向量执行数组计算查看文档 画图添加注释 实践导入数据关系运算符分支恒星运动 matlab 学习看入门之旅 先计算等号右边再计算等号左边。 工作区记录等号右边的变量。 ; 表示的是抑制输出。…

vmvare虚拟机centos 忘记超级管理员密码怎么办?

vmvare虚拟机centos 忘记超级管理员密码怎么办?如何重置密码呢? 一、前置操作 重启vmvare虚拟机的过程中,长按住Shift键 选择第一个的时候,按下按键 e 进入编辑状态。 然后就会进入到类似这个界面中。 在下方界面 添加 init=/bin/sh,然后按下Ctrl+x进行保存退出。 init=/bi…

编码能力提升计划 - 华为OD统一考试(E卷)

2024华为OD机试(E卷+D卷+C卷)最新题库【超值优惠】Java/Python/C++合集 题目描述 为了提升软件编码能力,小王制定了刷题计划,他选了题库中的n道题,编号从0到n-1,并计划在m天内按照题目编号顺序刷完所有的题目(注意,小王不能用多天完成同一题)。 在小王刷题计划中,小王…

CSS样式基础样式选择器

目录 1.css样式的规则 2.引入css样式的方式 1)行内式 2)内嵌式 3)外链式 1-link导入 2-import导入 4)总 3.css基础选择器 1)标签选择器 案例&#xff1a;使用标签选择器编写一个圆 1.代码 2.效果 2)类选择器 案例&#xff1a;使用类选择器为div添加背景色 1.代码 2.效果 3)id…

如何使用ssm实现影院管理系统的设计与实现

TOC ssm751影院管理系统的设计与实现jsp 研究背景与现状 时代的进步使人们的生活实现了部分自动化&#xff0c;由最初的全手动办公已转向手动自动相结合的方式。比如各种办公系统、智能电子电器的出现&#xff0c;都为人们生活的享受提供帮助。采用新型的自动化方式可以减少…

多处理器的概念与对比

SISD, SIMD, MISD, 和 MIMD 代表了并行计算的四种基本架构&#xff0c;它们描述了处理器如何处理指令和数据。 理解这些架构的关键在于区分指令流&#xff08;Instruction Stream&#xff09;和数据流&#xff08;Data Stream&#xff09;是单一的还是多重的。 1. SISD (Singl…

怎样过好国庆节

今天是2024年10月1号&#xff0c;国庆节&#xff0c;七天小长假&#xff0c;估计每个人都有自己的小计划。有想出去浪的&#xff0c;有想闭关修炼的&#xff0c;有想约会恋爱的&#xff0c;也有想回家看父母的&#xff0c;只要有事干&#xff0c;有想法&#xff0c;有行动&…

【JavaEE】——多线程常用类

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 引入&#xff1a; 一&#xff1a;Callable和FutureTask类 1&#xff1a;对比Runnable 2&#xff1a…

多模态大模型 Qwen2-VL 下载、推理、微调实战案例来了

文章目录 技术交流Qwen2-VL 有什么新功能&#xff1f;模型结构模型效果模型下载模型推理模型微调 最近这一两周看到不少互联网公司都已经开始秋招发放Offer。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c…

c#增删改查 (数据操作的基础)

//数据操作无非4种 //增删改查 是数据操作的基础 int[] ints { 110, 120, 119 }; //1. 查 在这里就是获取数组中的数据 int num ints[1]; //将数组中的某个元素取出来 Console.WriteLine(num); //2. 改 将数据从…

【C++并发入门】opencv摄像头帧率计算和多线程相机读取(下):完整代码实现

前言 高帧率摄像头往往应用在很多opencv项目中&#xff0c;今天就来通过简单计算摄像头帧率&#xff0c;抛出一个单线程读取摄像头会遇到的问题&#xff0c;同时提出一种解决方案&#xff0c;使用多线程对摄像头进行读取。上一期&#xff1a;【C并发入门】摄像头帧率计算和多线…

Elasticsearch使用Easy-Es + RestHighLevelClient实现深度分页跳页

注意&#xff01;&#xff01;&#xff01;博主只在测试环境试了一下&#xff0c;没有发到生产环境跑。因为代码还没写完客户说不用弄了( •̩̩̩̩&#xff3f;•̩̩̩̩ ) 也好&#xff0c;少个功能少点BUG 使用from size的时候发现存在max_result_window10000的限制&…

认知杂谈67《耐心!征服世界的秘籍》

内容摘要&#xff1a; 人生需家人朋友支持&#xff0c;自信源于解决问题的实力。别怕挫折&#xff0c;努力向前&#xff0c;反思自我。人生如游戏&#xff0c;靠自己打拼。学习要提升沟通、逻辑思维和时间管理等技能&#xff0c;读经典书籍&#xff0c;在平台学编程等&#xff…

ThreadLocal内存泄漏分析

一、ThreadLocal内存泄漏分析 1.1 ThreadLocal实现原理 1.1.1、set(T value)方法 查看ThreadLocal源码的 set(T value)方法&#xff0c;可以发现数据是存在了ThreadLocalMap的静态内部类Entry里面 其中key为使用弱引用的ThreadLocal实例&#xff0c;value为set传入的值。核…

C for Graphic:DNF手游残影效果

dnf手游在作死的道路上越行越远&#xff0c;困难罗特斯完全打不动&#xff0c;提前在抖音上细看攻略&#xff0c;基本能躲过机制不死&#xff0c;但是伤害不够&#xff0c;全时打满也还剩3000管血&#xff0c;组团半天炸团半天完全浪费一天。 个人觉得策划完全没必要这么逼…