【五】Netty 传输Java对象

news2024/11/19 6:20:58

Netty 传输Java对象

  • 介绍
  • 业务场景模拟
    • 流程图
  • 代码展示
    • 订购采购消息 POJO 类
    • 订购应答消息 POJO 类
    • 服务端启动类 SubscribeReqServer
    • 服务端业务处理类 SubscribeServerHandler
    • 客户端启动类 SubscribeClient
    • 客户端 业务处理类 SubscribeClientHandler
  • 效果展示
    • 服务端打印
    • 客户端打印
  • 总结

介绍

我们Java 程序员接触到的第一种序列化或者编码技术 应该 就是Java的默认序列化,只需要序列化的POJO对象实现 java.io.Serializable接口,根据实际情况生成序列 serialVersionUID ,这个类就能通过 java.io.ObjectInput和 java.io.ObjectOutput序列化和反序列化。但是jdk自带的序列化和反序列化 的性能非常差,而且不支持夸语言传输,所以很多场景我们都不使用它。现在让我们利用netty 来实现 java对象的序列化吧。

业务场景模拟

流程图

在这里插入图片描述
(1)Netty 服务端接收客户端的用户订购请求信息,消息定义如下
在这里插入图片描述
(2)服务端接收到请求消息,对用户名进行合法性校验,如果合法,则构造订购成功的应答消息给客户端,订购应答消息定义如下:
在这里插入图片描述

代码展示

订购采购消息 POJO 类

public class SubscribeReq implements Serializable {
    private static final long serialVersionUID=1L;
    //订购编号
    private int subReqID;
    //用户名
    private String userName;
    //订购的产品名称
    private String productName;
    //订购者的电话号码
    private String phoneNumber;
    //订购者的家庭地址
    private String address;


    public int getSubReqID() {
        return subReqID;
    }

    public void setSubReqID(int subReqID) {
        this.subReqID = subReqID;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String toString(){
        return "SubscribeReq [ subReqID = "+subReqID+" , userName = " +
                ""+userName+" , productName = "+productName+" ," +
                " phoneNumber = "+phoneNumber+" , address = "+address+" ]";
    }
}

订购应答消息 POJO 类

public class SubscribeResp implements Serializable {
    private static final long serialVersionUID=1L;
    //订购编号
    private int subReqID;
    //订购结果 0 表示成功
    private int respCode;
    //可选的详细描述信息
    private String desc;

    public int getSubReqID() {
        return subReqID;
    }

    public void setSubReqID(int subReqID) {
        this.subReqID = subReqID;
    }

    public int getRespCode() {
        return respCode;
    }

    public void setRespCode(int respCode) {
        this.respCode = respCode;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String toString(){
        return "SubscribeResp [ subReqID = "+subReqID+" " +
                ", respCode = "+respCode+" , desc = "+desc+" ]";
    }
}

服务端启动类 SubscribeReqServer

public class SubscribeReqServer {
    public void bind(int port){
        //配置服务端的NIO线程组
        EventLoopGroup parentGroup=new NioEventLoopGroup();
        EventLoopGroup childGroup=new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap=new ServerBootstrap();
            bootstrap.group(parentGroup,childGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,100)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                           // ObjectDecoder 负责对实现 Serializable 的POJO对象进行解码
                            // 有多个构造函数,支持不同的ClassResolver,在此我们使用 weakCachingConcurrentResolver
                            //来创建线程安全的WeakReferenceMap对类加载器进行缓存,支持多线程并发访问
                            //为了防止异常码流和解码错位导致的内存溢出,这里将单个对象最大序列化后的字节数组长度设置为1M
                            socketChannel.pipeline()
                                    .addLast(new ObjectDecoder(1024*1024,
                                            ClassResolvers.weakCachingConcurrentResolver(
                                                    this.getClass().getClassLoader())));
                            // ObjectEncoder,它可以在消息发送的时候自动将实现了Serializable 接口的
                            //POJO对象进行编码,因此用户无需亲自对对象进行手工序列化,只需要关注自己的业务逻辑即可
                            socketChannel.pipeline()
                                    .addLast(new ObjectEncoder());
                            socketChannel.pipeline()
                                    .addLast(new SubscribeServerHandler());
                        }
                    });
            ChannelFuture future=bootstrap.bind(port).sync();
            System.out.println("netty server is started");
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //优雅退出,释放线程池资源
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new SubscribeReqServer().bind(8080);
    }
}

服务端业务处理类 SubscribeServerHandler

public class SubscribeServerHandler extends ChannelHandlerAdapter {

    public void channelRead(ChannelHandlerContext context,Object obj){
        SubscribeReq subscribeReq=(SubscribeReq)obj;
        //对合法性进行交易,当前只校验userName属性。如果符合,将信息发送给客户端
        if ("echo".equals(subscribeReq.getUserName())){
            System.out.println("Service accept client subscribe req : "+subscribeReq);
            context.writeAndFlush(resp(subscribeReq.getSubReqID()));
        }
    }

    private SubscribeResp resp(int subId){
        SubscribeResp subscribeResp=new SubscribeResp();
        subscribeResp.setSubReqID(subId);
        subscribeResp.setRespCode(0);
        subscribeResp.setDesc("Netty learning is doing,please go on .");
        return subscribeResp;
    }

    public void exceptionCaught(ChannelHandlerContext context,Throwable throwable){
        throwable.printStackTrace();
        context.close();
    }


}

客户端启动类 SubscribeClient

public class SubscribeClient {

    private void connect(String host, int port) {
        EventLoopGroup workGroup = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workGroup)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(
                                    new ObjectDecoder(1024,
                                            ClassResolvers.cacheDisabled(this.getClass().getClassLoader()))
                            );
                            socketChannel.pipeline().addLast(new ObjectEncoder());
                            socketChannel.pipeline().addLast(new SubscribeClientHandler());

                        }
                    });
            ChannelFuture future=bootstrap.connect(host,port).sync();
            System.out.println("the netty client is started,and connected server");
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //优雅退出
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new SubscribeClient().connect("127.0.00.1",8080);
    }
}

客户端 业务处理类 SubscribeClientHandler

public class SubscribeClientHandler extends ChannelHandlerAdapter {

    //tcp 链接成功后,就给服务端 循环发送10条信息
    public void channelActive(ChannelHandlerContext context){
        for (int i=0;i<10;i++){
            context.write(subReq(i));
        }
        context.flush();
    }

    private SubscribeReq subReq(int i){
        SubscribeReq subscribeReq=new SubscribeReq();
        subscribeReq.setSubReqID(i);
        subscribeReq.setAddress("深圳市宝安区西乡街道xxx");
        subscribeReq.setPhoneNumber("174868xxxx");
        subscribeReq.setProductName("Netty learning ");
        subscribeReq.setUserName("echo");
        return  subscribeReq;
    }

    /**
     * 由于对象解码器已经对 SubscribeResp 请求消息 进行了自动解码,
     * 因此
     * @param context
     * @param obj
     */
    public void channelRead(ChannelHandlerContext context,Object obj){
        System.out.println("Receive server response : "+obj);
    }


}

效果展示

服务端打印

在这里插入图片描述

客户端打印

在这里插入图片描述

总结

本章介绍了如何利用Netty 提供的ObjectEncoder编码器和ObjectDecoder解码器实现对普通POJO对象的序列化。通过上面的例子,我们学习了服务端和客户端的开发,并且模拟了TCP的粘包和拆包场景。还是很方便的实现了功能。利用Netty ,我们可以更多的关注自己的业务逻辑,而不用考虑这些粘包和拆包的底层问题

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

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

相关文章

20230109网安陈之琳材料大纲-web渗透

目录 引言 正文 信息收集 端口扫描 敏感目录的扫描 主机漏洞扫描 常见的漏洞及防御 SQL注入漏洞 目录遍历漏洞/文件包含漏洞 提权 删日志 引言 首先呢&#xff0c;经过我本人对此篇论文的研读&#xff0c;发现此篇论文属于web方向的一篇入门文章 梁本来前辈对常见…

使用Docker Compose一键部署前后端分离项目

目录 一、安装Docker和docker Compose &#xff08;1&#xff09;Docker安装 &#xff08;2&#xff09;Docker Compose安装 &#xff08;3&#xff09;查看版本信息 二、准备工作 1. 新建工作目录 2. 工作目录结构 3. 后台打包 4. 前台打包 5. 数据库文件上传 6. 编…

Nginx反向代理和负载均衡配置

一.什么是反向代理 反向代理&#xff08;Reverse Proxy&#xff09;方式是指以代理服务器来接受Internet上的连接请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;并将从服务器上得到的结果返回给Internet上请求连接的客户端&#xff0c;此时代理服务器对外就…

Sentinel-限流 冷启动

概述 当流量突然增大的时候&#xff0c;我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态&#xff0c;我们希望处理请求的数量是缓步的增多&#xff0c;经过预期的时间以后&#xff0c;到达系统处理请求个数的最大值。Warm U…

在Mac上配置Vue开发环境

因为Vue是NodeJS的模块&#xff0c;要想使用Vue需要先安装NodeJS 在Mac中安装NodeJS通过brew包管理器就会很方便, 因为访问源速度问题建议使用5&#xff08;阿里&#xff09;&#xff0c;Homebrew开源项目地址&#xff1a;https://gitee.com/cunkai/HomebrewCN/blob/master/REA…

千锋教育+计算机四级网络-计算机网络学习-02

目录 分组交换的两种传输方式 数据报方式 ​编辑 虚电路方式 OSI参考模型 IP地址分类 公有IP 私有IP 回环ip地址 子网掩码 端口 端口号 端口分类 数据包的组装、拆解 网络应用程序开发流程 选择合适的协议&#xff08;TCP或UDP) TCP—面向连接 UDP—面向无连接 …

第八章面向对象编程(中级)

8.1访问修饰符 8.1.1基本介绍 java提供四种访问控制修饰符号&#xff0c;用于控制方法和属性&#xff08;成员变量&#xff09;的访问权限&#xff08;范围&#xff09;&#xff1a; 公开级别:用 public 修饰,对外公开受保护级别:用 protected 修饰,对子类和同一个包中的类公开…

基于Docker安装Nginx

基于Docker安装Nginx 1.安装Nginx 先启动一个 Nginx 实例, 可以得到相关配置 1.这里我将安装的软件放在/mydata目录下 #进入mydata目录 cd mydata/ #创建nginx目录 mkdir nginx # 拉取nginx 1.10版本镜像并允许容器 docker run -p 80:80 --name nginx -d nginx:1.10将容器内…

RHCE第四天之Web服务器详解

文章目录一、网址及HTTP简介二、www服务器的类型三、 www服务器的基本配置四、基于https协议的静态网站五、实验练习web服务器提供的数据大部分都是文件&#xff0c;那么我们需要在服务器端先将数据文件写好&#xff0c;并且放置在某个特殊的目录下面&#xff0c;这个目录就是我…

Profiler导致的严重性能问题

背景客户反馈系统突然运行非常缓慢&#xff0c;持续了近20分钟的时间&#xff0c;通过SQL专家云定位到有人开启了Profiler导致&#xff0c;但是不能定位是谁开启的&#xff0c;请我们协助分析。现象登录SQL专家云&#xff0c;进入实时可视化页面&#xff0c;在活动会话中看到在…

【Ctfer训练计划】——(十)

作者名&#xff1a;Demo不是emo主页面链接&#xff1a; 主页传送门创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

智公网:这几类人员报考公务员无法被录取

对于很多人来讲&#xff0c;毕业之后都想找一份稳定的工作&#xff0c;目前最受欢迎的就是公务员和教师编了&#xff0c;我们今天来说下公务员这个铁饭碗。 公务员考试可是很不容易的&#xff0c;有两场考试&#xff0c;第一场是笔试&#xff0c;第二场是面试。笔试通过之后才…

2021-06-10 Multisim的74LS192功能表及555时基74LS190

缘由https://ask.csdn.net/questions/7445811?spm1005.2025.3001.5141以及60s倒计时电路连接后没有显示 - 24小时必答区 74LS192芯片是一个具有双计数功能的芯片&#xff0c;既可以做加计数&#xff0c;也可以做减计数。 1、A、B、C、D 置数输入端&#xff0c;管脚悬空相当…

Web端接入视频设备(NVR/IPC)

概述 本文主要介绍视频监控设备&#xff0c;视频监控设备接入&#xff0c;常用的开源流媒体及接入过程中的一些问题。 第一章 视频监控设备 目前常见的视频监控设备主要有NVR和IPC&#xff0c;以海康为例。 1.1 视频监控设备介绍 IPC即IP Camera&#xff0c;可以接入网络的…

06-GC垃圾收集器有那些?

如图展示了HotSpot虚拟机中7种不同的垃圾收集, 连线代表两者可搭配使用 1.Serial 垃圾收集器&#xff08;单线程、复制算法&#xff09; Serial&#xff08;英文连续&#xff09;是最基本垃圾收集器&#xff0c;使用复制算法&#xff0c;曾经是JDK1.3.1 之前新生代唯一的垃圾…

【基础】Flink -- DataStream API

Flink -- DataStream API执行环境 Execution Environment创建执行环境设置执行模式触发程序执行源算子 Source从集合中读取数据从文件读取数据从 Socket 读取数据自定义数据源转换算子 Transformation基本转换算子映射 map过滤 filter扁平映射 flatMap聚合算子 Aggregation按键…

WPS配置mathtype

笔者电脑软件版本&#xff1a;WPS Office mathtype_7.4.8.0 请注意WPS适配的mathtype版本。 下载地址 mathtype_7.4.8.0&#xff1a;https://wwl.lanzoum.com/iuJDz0guffuh wps.vba.exe&#xff1a;https://handong1201.lanzouw.com/iX5GZtn70pe&#xff08;mathtype右侧选…

查找算法之线性查找

目录 线性查找 算法实现 算法实现 python C 复杂度分析 优点与缺点 线性查找 线性查找&#xff08;Linear Search&#xff09;是一种最基础的查找方法&#xff0c;其从数据结构的一端开始&#xff0c;依次访问每个元素&#xff0c;直到另一端后停止。 算法实现 线性查…

【凸优化】Gradient Descent and Newton Descent【梯度下降法和牛顿下降法】(含Python代码绘制等高线图)

文章目录Gradient Descent and Newton Descent一、下降法【Descent】二、梯度下降法【Gradient Descent】三、牛顿下降法【Newton Descent】四、示例Example五、ReferenceGradient Descent and Newton Descent 一、下降法【Descent】 首先介绍什么是下降法【Descent Methods】…

【Git】下载安装学习记录

【下载安装】 1.官网下载64位的安装包 2.双击安装&#xff0c;设置安装路径&#xff0c;一路next即可 使用学习指南&#xff1a;一、设置用户签名二、操作本地库的命令git initgit statusgit add 文件名git rm --cached 文件名git commit -m "注释" 文件名git refl…