netty学习(5):netty实现注册中心和发送JSON数据到指定的客户端

news2024/11/15 6:53:06

1. 实现:在netty客户端实现netty客户端注册功能,netty客户端需要发送注册消息到netty服务端。

2. 在父工程创建Message类,定义消息格式和消息类型

定义消息类型:

package message;

public enum MessageType {
    RegisterRequest,
    RegisterResponse,

    QueryRegisterRequest,
    QueryRegisterResponse,

    Request,
    Response
}

定义Message

package message;

import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

@Data
public class Message extends JSONObject {
    private String uuid;
    private MessageType messageType;
    private String from; //消息来源
    private String to;
    private JSONObject data; //消息实体
    private JSONObject message = new JSONObject();

    public Message(MessageType messageType, String from, String to, JSONObject data) {
        this.uuid = UUID.randomUUID().toString();
        this.messageType = messageType == null ? MessageType.Request : messageType;
        this.from = from;
        this.to = to;
        this.data = data;
        message.put("uuid", this.uuid);
        message.put("messageType", messageType);
        message.put("from", from);
        message.put("to", to);
        message.put("data", data);
    }

    //序列化
    public byte[] toByte() {
        System.out.println("message:" + this.message.toJSONString());
        return this.message.toJSONString().getBytes(StandardCharsets.UTF_8);
    }

    //反序列化
    public static Message toMessage(String msg) {
        return (Message) JSONObject.parseObject(msg);
    }

    public String toString() {
        return this.message.toJSONString();
    }
}

3. 服务端实现注册中心

创建Register类,管理注册的客户端

package server.register;

import io.netty.channel.Channel;
import java.util.HashMap;

public class Register {
    private static HashMap<String, Channel> registerTable = new HashMap<>();

    private Register() {

    }

    public static void addServer(String name, Channel channel) {
        registerTable.put(name, channel);
        System.out.println(name + "注册成功!");
    }

    public static void removeServer(String name, Channel channel) {
        registerTable.remove(name);
    }

    public static Channel getServer(String name) {
        return registerTable.get(name);
    }

    public static HashMap<String, Channel> getAllServer() {
        return registerTable;
    }
}

修改NettyServiceHandler,对服务器接收的消息根据类型处理,如果是注册消息,则去注册,请求消息则发送到相应的客户端。

package server.netty;

import com.alibaba.fastjson.JSONObject;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import server.register.Register;

import java.util.HashMap;

public class NettyServiceHandler extends SimpleChannelInboundHandler<String> {
    private static final ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 获取到当前与服务器连接成功的channel
        Channel channel = ctx.channel();
        group.add(channel);
        System.out.println(channel.remoteAddress() + " 上线," + "在线数量:" + group.size());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 获取到当前要断开连接的Channel
        Channel channel = ctx.channel();
        System.out.println(channel.remoteAddress() + "下线," + "在线数量:" + group.size());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Channel channel = ctx.channel();
        System.out.println("netty客户端" + channel.remoteAddress() + "发送过来的消息:" + msg);
        JSONObject message = JSONObject.parseObject(msg);
//        group.forEach(ch -> { // JDK8 提供的lambda表达式
//            if (ch != channel) {
//                ch.writeAndFlush(msg + "\r\n");
//            }
//        });
        HandlerMessage(message, channel);
    }

    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
        throwable.printStackTrace();
        channelHandlerContext.close();
    }

    public void HandlerMessage(JSONObject message, Channel channel) {
        String messageType = message.getString("messageType");
        switch (messageType) {
            case "RegisterRequest":
                message.put("channel", channel);
                register(message);
                break;
            case "QueryRegisterRequest":
                break;
            default:
                request(message);
        }
    }

    public void register(JSONObject message) {
        Register.addServer(message.getString("from"), (Channel) message.get("channel"));
    }

    public void request(JSONObject message) {
        Channel channel = Register.getServer(message.getString("to"));
        channel.writeAndFlush(message.toJSONString() + "\r\n");
    }

    public HashMap<String, Channel> queryRegister() {
        return Register.getAllServer();
    }
}

4. 客户端自动注册

客户端启动时把自己的信息发送到服务端

package client.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import message.Message;
import message.MessageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
@Slf4j
public class NettyClient {
    public final static Logger logger = LoggerFactory.getLogger(NettyClient.class);

    @Resource
    private SocketInitializer socketInitializer;

    @Getter
    private Bootstrap bootstrap;

    @Getter
    private Channel channel;

    /**
     * netty服务监听端口
     */
    @Value("${netty.port:6666}")
    private int port;

    @Value("${netty.host:127.0.0.1}")
    private String host;

    @Value("${netty.name}")
    private String name;
    /**
     * 启动netty
     */
    public void start() {
        this.init();
        this.channel = this.bootstrap.connect(host, port).channel();
        logger.info("Netty connect on port: {}, the host {}, the channel {}", this.port, this.host, this.channel);
        //自动注册
        register();
    }

    /**
     * 初始化netty配置
     */
    private void init() {
        EventLoopGroup group = new NioEventLoopGroup();
        this.bootstrap = new Bootstrap();
        //设置线程组
        bootstrap.group(group)
                .channel(NioSocketChannel.class) //设置客户端的通道实现类型
                .handler(this.socketInitializer);
    }

    //netty发送消息
    public void sendMessage(String message) {
        this.channel.writeAndFlush(message + "\r\n");
    }

    //netty发送消息
    public void sendMessage(Message message) {
        this.channel.writeAndFlush(message.toString() + "\r\n");
    }

    public void register() {
        Message message = new Message(MessageType.RegisterRequest, name, null, null);
        sendMessage(message);
        logger.info("register");
    }
}

5. 客户端RestController层接收消息

RESTFUL风格,从url解析目标客户端的名称

package client.control;

import client.netty.NettyClient;
import com.alibaba.fastjson.JSONObject;
import message.Message;
import message.MessageType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;

@RestController
@RequestMapping("/client1")
public class NettyControl {
    @Value("${netty.name}")
    private String from;

    @Resource
    private NettyClient nettyClient;

    @PostMapping("/{to}/msg")
    public String sendMsg(@PathVariable("to") String to, @RequestBody JSONObject data) {
        Message message = new Message(MessageType.Request, from, to, data);
        this.nettyClient.sendMessage(message);
        return message.toString();
    }
}

6. postman测试

启动服务和两个客户端,客户端已经注册成功。
在这里插入图片描述
client1发送到client2
在这里插入图片描述
在这里插入图片描述
client2发送到client1
在这里插入图片描述
在这里插入图片描述
服务端收到的消息
在这里插入图片描述

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

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

相关文章

函数重载与函数递归

一、函数重载 定义&#xff1a;两个函数的函数名称相同&#xff0c;但是参数的个数或者类型不同 参考以下代码&#xff1a; //1.public static int add(int x,int y){return x y;}//2.与1构成重载public static int add(byte a,int b){return a b;}//3.与1构成重载public s…

文件上传漏洞总结

文件上传 文件上传漏洞产生的原理 文件上传漏洞是指用户通过界面上的上传功能上传了一个可执行的脚本文件&#xff0c;而WEB端的系统并未对其进行检测或者检测的逻辑做的不够好。 文件上传漏洞的危害 1、由于是上传的文件&#xff0c;所以文件由用户决定&#xff0c;上传we…

交换机架构整理

网口的基本结构 网口扫盲三:以太网芯片MAC和PHY的关系 问:如何实现单片以太网微控制器? 问:以太网MAC是什么? 问:什么是MII? 问:以太网PHY是什么? 问:造成以太网MAC和PHY单片整合难度高的原因是什么? 问: 网卡上除RJ-45接口外,还需要其它元件吗? 问:10BaseT和100BaseTX…

LeetCode[面试题17.14]最小的K个数

难度&#xff1a;中等 题目&#xff1a; 设计一个算法&#xff0c;找出数组中最小的k个数。以任意顺序返回这k个数均可。 示例&#xff1a; 输入&#xff1a; arr [1,3,5,7,2,4,6,8], k 4 输出&#xff1a; [1,2,3,4]提示&#xff1a; 0 < len(arr) < 1000000 <…

Java设计模式之创建型-建造者模式(UML类图+案例分析)

目录 一、基本概念 二、UML类图 三、角色设计 四、案例分析 五、总结 一、基本概念 建造者模式是一种创建型设计模式&#xff0c;它使我们将一个复杂对象的构建步骤分离出来&#xff0c;使得同样的构建过程可以创建不同的表示。该模式的目的是将构建复杂对象的过程抽象化…

JavaScrpt_13 Web API 正则表达式

JavaScrpt_13 Web API 正则表达式 一、 正则表达式1. 正则基本使用2. 元字符边界符量词范围字符类 3. 替换和修饰符4. change 事件5. 判断是否有类 一、 正则表达式 正则表达式&#xff08;Regular Expression&#xff09;是一种字符串匹配的模式&#xff08;规则&#xff09;…

12_Linux异步通知

目录 异步通知简介 驱动中的信号处理 应用程序对异步通知的处理 驱动程序编写 编写测试APP 运行测试 异步通知简介 在使用阻塞或者非阻塞的方式来读取驱动中按键值都是应用程序主动读取的,对于非阻塞方式来说还需要应用程序通过poll函数不断的轮询。最好的方式就是驱动…

【Python爬虫与数据分析】时间、日期、随机数标准库

目录 一、模块化概述 二、time库 1. 时间获取 2. 时间格式化 3. 程序计时 三、datetime库 1. datetime.datetime类 2. datetime.timedelta类 四、random库 1. 基本随机函数 2. 扩展随机函数 3. 随机时间的生成 一、模块化概述 Python程序由模块组成&#xff0c;一个…

MySQL基础篇第4章(运算符)

文章目录 1、算术运算符1.1 加法与减法运算符1.2 乘法与除法运算符1.3 求模&#xff08;求余&#xff09;运算符 2、比较运算符2.1 等号运算符2.2 安全等于<>2.3 不等于运算符2.4 空运算符2.5 非空运算符2.6 最小值运算符2.7 最大值运算符2.8 BETWEEN AND运算符2.9 IN运算…

typeScript(持续吐血版)

typeScript-02-进阶(TSVue3) 结合vue3来使用TypeScript 使用vite来创建vue3TS的项目 使用vite创建项目&#xff0c;并选择带ts的版本 npm create vitelatest my-vue-ts-app – --template vue-ts 参考链接&#xff1a;https://vuejs.org/guide/typescript/composition-api…

7.软件是怎么样炼成的:c++编译器过程

"重新生成解决方案"&#xff0c;"调试"的背后的四个阶段 故事&#xff1a; 渣男是有套路和步骤的。 代码变成软件也是有固定的套路的 总结&#xff1a; 1.预处理 g -e源程序&#xff0c;-o生成的结果。后面的a.cpp是新的源文件。这个时候还是源程序计算…

leetcode-977. 有序数组的平方

leetcode-977. 有序数组的平方 文章目录 leetcode-977. 有序数组的平方一.题目描述二.第1次提交(std::sort)三.第2次提交(左右指针) 一.题目描述 二.第1次提交(std::sort) class Solution {public:vector<int> sortedSquares(vector<int> &nums) {for (int i …

Centos或Linux编写一键式Shell脚本删除用户、组指导手册

文章目录 一、目的二、操作步骤 一、目的 本指导手册为了更加方便使用Centos或者Linux&#xff0c;并在里面删除用户、用户组。 注意点1&#xff1a;userdel命令删除该用户时&#xff0c;并不能删除该用户的所有信息&#xff0c;只是删除了/etc/passwd、/etc/shadow、/etc/gr…

Vue3 +TScript 基本开发

首先你要使用 vite 创建项目 npm init vuelatest 并选择带ts的版本 文件的结构 main.ts 文件 import { createApp } from "vue" import { createPinia } from piniaimport App from "./App.vue" const pinia createPinia() const app createApp(App)a…

map、multimap、set、multiset讲解

文章目录 &#x1f4cd;前言1. 关联式容器2. 键值对3. 树形结构的关联式容器3.1 set3.1.1 set的介绍3.1.2 set的使用 3.2 map3.2.1 map的介绍3.2.2 map的使用 3.3 muitiset3.3.1 multiset的介绍3.3.2 multiset的使用 3.4 multimap3.4.1 multimap的介绍3.4.2 multimap的使用 3.5…

山西电力市场日前价格预测【2023-07-10】

日前价格预测 预测明日&#xff08;2023-07-10&#xff09;山西电力市场全天平均日前电价为374.23元/MWh。其中&#xff0c;最高日前价格为417.10元/MWh&#xff0c;预计出现在19: 45。最低日前电价为323.51元/MWh&#xff0c;预计出现在13: 30。 价差方向预测 1&#xff1a;实…

利用VitePress部署静态网站

前言 之前看到过很多这样的静态网站&#xff0c;基于Markdown格式&#xff0c;风格基本统一&#xff0c;而且这种网站非常常见&#xff0c;例如&#xff1a; 例如&#xff0c;以下的几个网址&#xff1a; Java HashMap 源码分析 | 未读代码BAT大厂面试题与全栈知识体系结合…

实践:devops之K8s环境持续部署

实践&#xff1a;devops之K8s环境持续部署 目录 推荐文章 https://www.yuque.com/xyy-onlyone/aevhhf?# 《玩转Typora》 1、Kubectl 发布流水线 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X2Q6MzL1-1688896509292)(https://bucket-hg.oss-cn-…

【唯一分解】A因子

A-因子_Wannafly挑战赛25 (nowcoder.com) 题意&#xff1a; 思路&#xff1a; Code&#xff1a; #include <bits/stdc.h>#define int long longusing namespace std;const int mxn1e510; const int mxe1e610; const int mod1e97; const int Inf1e18;int N,K; int len0;…

8 Java自增和自减

自增&#xff1a;i或i。 自减&#xff1a;i--或--i。 两种自增和自减的写法是有区别的&#xff0c;以自增为例子。i是先把未自增的i赋值给左边&#xff0c;i再进行自增&#xff0c;而i是先自增&#xff0c;再把自增后的i赋值给左边。自减的道理也是如此。 i的情况如下代码所示&…