netty学习(2):多个客户端与服务器通信

news2024/11/28 6:58:29

1. 基于前面一节netty学习(1):1个客户端与服务器通信

只需要把服务器的handler改造一下即可,通过ChannelGroup 找到所有的客户端channel,发送消息即可。

package server;

import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * 自定义处理Handler
 */
public class NettyServiceHandler extends SimpleChannelInboundHandler<String> {
    // 创建一个ChannelGroup,其是一个线程安全的集合,其中存放着与当前服务器相连接的所有Active状态的Channel
    // GlobalEventExecutor是一个单例、单线程的EventExecutor,是为了保证对当前group中的所有Channel的处理
    // 线程是同一个线程
    private static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    // 只要有客户端Channel与服务端连接成功就会执行这个方法
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 获取到当前与服务器连接成功的channel
        Channel channel = ctx.channel();
        System.out.println(channel.remoteAddress() + "---上线");
        group.writeAndFlush(channel.remoteAddress() + "---上线\n");
        // 将当前channel添加到group中
        group.add(channel);

//        NettyService.remoteAddressMap.put(channel.remoteAddress().toString(), ctx);
    }

    // 只要有客户端Channel断开与服务端的连接就会执行这个方法
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 获取到当前要断开连接的Channel
        Channel channel = ctx.channel();
        System.out.println(channel.remoteAddress() + "------下线");
        group.writeAndFlush(channel.remoteAddress() + "下线,当前在线人数:" + group.size() + "\n");

        // group中存放的都是Active状态的Channel,一旦某Channel的状态不再是Active,
        // group会自动将其从集合中踢出,所以,下面的语句不用写
        // remove()方法的应用场景是,将一个Active状态的channel移出group时使用
        // group.remove(channel);
    }

    /**
     * channelRead,这个方法当有数据读写的时候,会触发,可以读取客户端的消息
     * 只要有客户端Channel给当前的服务端发送了消息,那么就会触发该方法的执行
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Channel channel = ctx.channel();
        System.out.println("netty客户端" + channel.remoteAddress() + "发送过来的消息:" + msg);
//        channel.writeAndFlush("自己发的消息:" + msg + "\n");

        group.forEach(ch -> { // JDK8 提供的lambda表达式
            if (ch != channel) {
                ch.writeAndFlush(channel.remoteAddress() + ":" + msg + "\n");
            } else {
                channel.writeAndFlush("自己发的消息:" + msg + "\n");
            }
        });
//        String[] split = msg.split(":");
//        if (split.length >= 2) { //指定客户端时发送给指定客户
//            System.out.println("发送给客户:" + split[0]);
//            if (NettyService.userIdMap.get(split[0]) != null) {
//                NettyService.userIdMap.get(split[0]).writeAndFlush(channel.remoteAddress() + ":" + split[1] + "\n");
//            } else {
//                NettyService.userIdMap.put(split[0], ctx);  //第一次发送消息时注册客户端的channel
//            }
//        } else { //否则发送给所有的客户端
//            System.out.println("广播");
//            // 遍历channelGroup,从而区分“我”和“别人”发出的消息,如果消息是自己发出的就显示“我”
//            group.forEach(ch -> { // JDK8 提供的lambda表达式
//                if (ch != channel) {
//                    ch.writeAndFlush(channel.remoteAddress() + ":" + msg + "\n");
//                } else {
//                    channel.writeAndFlush("自己发的消息:" + msg + "\n");
//                }
//            });
//        }
    }
    /**
     * channelReadComplete,数据读取完毕之后,需要做的业务操作,回消息
     */
//    public void channelReadComplete(ChannelHandlerContext channelHandlerContext) throws Exception {
//        //消息出站
//        System.out.println("Netty服务端读取消息完毕");
//        channelHandlerContext.writeAndFlush(Unpooled.copiedBuffer("--over", CharsetUtil.UTF_8));
//    }

    /**
     * exceptionCaught,发生异常的handler
     */
    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
        throwable.printStackTrace();
        channelHandlerContext.close();
    }
}

2. 测试

创建3个客户端

package test;

import client.NettyClient;

public class Client3 {
    public static void main(String[] args) {
        new NettyClient("127.0.0.1",6666).createNettyClient();
    }
}

每个客户端都发送消息
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
服务器
在这里插入图片描述

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

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

相关文章

群晖GitLab修改clone(克隆)地址

通过群晖的Docker(ContainerManager)配置好GitLab后&#xff0c;每次clone代码总要修改前面的地址&#xff0c;因此作者找到了修改的办法&#xff0c;实属不易&#xff0c;请给个关注&#xff01; 给出我的群晖配置gitlab的设置&#xff0c;如图1。 图1 Docker中GitLab的配置 按…

生成式AI筑建基石,亚马逊云科技以强大应用能力和辐射范围加快技术传播速度

众所周知&#xff0c;要把大模型转化为生产力&#xff0c;AI模型、算力和数据会是难以逾越的门槛。新的目标已经出现&#xff0c;我们是否有了足够强大的AI基础设施&#xff1f;在6月28日上海举行的峰会上&#xff0c;亚马逊云科技展示了这样的能力。 从掀起AI画图热潮的Stabil…

禁用USB接口的几个办法

本文为大家提供了四个禁用电脑USB接口的方法&#xff0c;如果企业用户建议使用方法三&#xff0c;方法三可以批量对公司内部所有电脑的usb接口进行禁用。 方法一&#xff1a;使用设备管理器禁用USB接口 步骤1&#xff1a;打开设备管理器 首先&#xff0c;我们需要打开设备管理…

玩转smardaten | 速来围观CSDN万粉博主如何零代码开发学生管理系统?

编者荐语&#xff1a; “开发软件必须写代码吗&#xff1f;有没有真正不写代码的快速开发工具&#xff1f;”这是CSDN测试开发领域的万粉博主曲鸟一直思考的问题。今年5月底接触到smardaten&#xff0c;仅用3天自学配置&#xff0c;开发出一款学生管理系统。不得不说&#xff…

python自动化测试 - 自动化框架及工具

1 概述 手续的关于测试的方法论&#xff0c;都是建立在之前的文章里面提到的观点&#xff1a; 功能测试不建议做自动化接口测试性价比最高接口测试可以做自动化 后面所谈到的 测试自动化 也将围绕着 接口自动化 来介绍。 本文选择的测试语言是 python 脚本语言。由于其官…

CentOS8安装docker容器

一、yum包更新到最新 [rootnginx /]# sudo yum update 若是出现以下异常; 处理&#xff1a; 1.首先&#xff0c;进入到 yum 的 repos 目录 [rootnginx /]# cd /etc/yum.repos.d/2.更新一下源。修改 centos 文件内容 [rootnginx yum.repos.d]# sed -i s/mirrorlist/#mirrorlist/…

Vue2+3入门到实战

作为IT技术相关行业不可或缺的岗位之一&#xff0c;前端开发工程师就业前途广阔&#xff0c;一直是很多同学心中转行的首选行业。但很多人还没开始&#xff0c;便被一系列问题难倒了&#xff0c;比如&#xff1a;前端该如何入门&#xff1f;路线图是怎样的&#xff1f;想要找到…

网络编程—— IP地址 + 端口号 +TCP/IP协议 + 协议分层的封装与应用

文章目录 前言一、网络发展各阶段二、网络通信的三大要素1.IP地址2.端口号3.网络协议 三、TCP/IP五层网络模型各层级的用处网络设备所在分层 四、封装和分用封装分用网络传输的实际情况 总结 前言 本人是一个刚刚上路的IT新兵,菜鸟!分享一点自己的见解,如果有错误的地方欢迎各…

如何提升你的小程序开发流程:实用的建议和技巧

随着微信小程序开发的兴起&#xff0c;越来越多的人想要开发自己的微信小程序&#xff0c;那么&#xff0c;如何提升你的微信小程序开发流程呢&#xff1f; 如果你还没有自己的小程序&#xff0c;那你现在就应该开始着手准备了。如果你已经有了自己的小程序&#xff0c;那么&a…

数字游牧民,连开会都如此“高科技”

你知道“数字游民”吗&#xff1f;是指无须到点上下班&#xff0c;旅居在悠闲惬意的海岛或乡村&#xff0c;通过互联网就能完成工作的群体&#xff0c;这样的工作模式便称作“数字游牧”。听起来很像社畜们的“梦中情job”&#xff0c;是近几年来全球流行的新型生活方式。 在疫…

学生体测的人体运动检测的mediapipe技术怎么实现?

Mediapipe是一个开源的跨平台框架&#xff0c;用于构建实时多媒体处理应用程序。它提供了一系列的预训练模型和工具&#xff0c;其中包括人体姿势估计模型&#xff0c;可以用于人体运动检测。 要使用Mediapipe进行人体运动检测&#xff0c;可以按照以下步骤进行&#xff1a; …

如何在多个 Linux 服务器上运行多个命令

动动发财的小手&#xff0c;点个赞吧&#xff01; 如果你正在管理多台 Linux 服务器&#xff0c;并且你想在所有 Linux 服务器上运行多个命令&#xff0c;但你不知道该怎么做。不用担心&#xff0c;在这个简单的服务器管理指南[1]中&#xff0c;我们将向您展示如何在多个 Linux…

CSS样式表

CSS样式表 1、CSS介绍 CSS Cascading Style Sheet 层叠样式表&#xff0c;或&#xff0c;级联样式表 表现HTML文件样式的计算机语言 修饰静态页面 配置脚本语言动态对网页元素进行样式格式化 排序 对元素的位置进行像素级精确控制 支持所有字体字号样式 对网页对象和模型样式…

rsync 远程同步

目录 一、 rsync 概念1.2 rsync 同步方式 二、rsync 特性三、 rsync与cp、scp对比配置rsync源服务器发起端下行同步发起端上行同步五、 rsyncinotify5.1 修改rsync源服务器配置文件5.2 调整发起端inotify内核参数5.3 安装 inotify-tools5.4 在另外一个终端编写触发式同步脚本&a…

代码随想录day7

四数之和II 力扣 思路&#xff1a; 这道题我们可以拆分为两个部分来做&#xff0c;首先计算前两个数组元素的和并且统计这个组合出现的次数&#xff0c;然后用0减掉后两个数组。 如果发现0减去后两个数组已经出现在我们之前记录出现次数的map中了&#xff0c;那么就可以说他们…

聊一聊人工智能与视频技术的5大发展趋势与应用

随着互联网的快速发展&#xff0c;视频时代已经到来。据统计&#xff0c;目前互联网内容中&#xff0c;视频内容占据高达82%的流量&#xff0c;未来仍将持续增长。今天我们就来聊一聊关于视频技术的发展&#xff0c;以及现在的大热门–人工智能技术与视频技术的结合。 视频技术…

使用家庭宽带和摄像头,实现公网直播

那天去逛商场看到有个营业厅&#xff0c;本想进去问问有没有存话费送话费的活动&#xff0c;结果被忽悠办了一个19.9升千兆宽带加送一个路由器的业务。 网络环境验证 听他们说现在家庭宽带都是有公网IPV6地址的&#xff0c;立马用电脑试了下确实有IPV6地址。 赶紧随便写了几行…

pytorch学习指南

安装anaconda&#xff1a; https://blog.csdn.net/fan18317517352/article/details/123035625 教程&#xff1a;bilibili up主&#xff1a;一只小土堆 构建pytorch空间 pytorch安装 查看cpu 安装命令pytorch&#xff1a;conda install pytorch torchvision torchaudio cpu…

SOLIDWORKS CSWA/CSWP认证考试培训

通过专业的培训和考试认证&#xff0c;可以让您多掌握一门软件的使用&#xff0c;让课程设计、毕业设计或科研工作多一个助手&#xff0c;在当前就业压力大的情况下提升自己的求职竞争力。 SOLIDWORKS CSWA/CSWP认证考试培训内容&#xff1a; 1、了解考试规则 2、认识考试题型…

数据结构--KMP之求next数组

数据结构–KMP之求next数组 next数组的作用:当模式串的第j个字符失配时&#xff0c;从模式串的第 next[j]的继续往后匹配 任何模式串都一样&#xff0c;第一个字符不匹配时&#xff0c;只能匹配下一个子串&#xff0c;因此&#xff0c;往后余生 \color{balck}任何模式串都一样…