Netty使用篇:自定义编解码器_netty自定义编码器和解码器-程序员宅基地

技术标签: # Netty专栏  java  服务器  开发语言  

在这里插入图片描述

我们今天还是继续Netty,Netty的编码器和解码器就是Netty对Handler这个组件的一种使用场景而已,SpringWebFlex就是基于这个Netty来做的,在往上引深一层GateWay服务网关就是SpringWebFlex的实现,所以SpringCloud当中明确说明了:Gateway不能和SpringWebStarter一起使用,引入了Gateway就不能引入后者,因为这是两种实现策略,常见的WebStater是Tomcat+JavaEE这套实现方式实现的。而webflex是基于Netty,不从属于传统JavaEE的这种开发方式。
看了很多Netty为我们提供的编解码器之后,我们如何自定义一个编解码器呢?
自定义编解码之上,能够自定义一套自己的通信协议呢?
制定了自定义协议之后,自定义编解码器必须需要我们自己定义了。

第一章:自定义编解码器的流程

在我们现在的开发来讲呢,我们需要客户端,我们假定客户端开发也是基于Java,我们也会有服务端。客户端和服务器端是需要通信的会有数据的往来,客户端和服务端都基于Java开发的话,我们关注的点是Java的类型,换句话说就是一个一个的Java类。最终,我们的数据也会封装到一个一个的Java类当中,我们跟服务端通信,通信的主旨是什么?就是将客户端封装好的类的对象的数据发送给服务端,服务端处理好之后,将业务数据封装成对象将对象数据发送给客户端。我们不可能在两个虚拟机当中传递我们的Java对象,这个过程当中都是讲Java对象转换为ByteBuf,这是Netty提供的类型,作为Netty将其中的数据取出来转成Byte数组,基于Socket流发送出去,作为服务器端呢,Netty会将Byte数组中的二进制数据转换为ByteBuf,然后将ByteBuf转换为Java类型(业务相关的对象类型)。

以上两个过程中涉及到我们的两部分内容了。一部分内容是Java类型转换为ByteBuf在Nerry体系当中称之为编码,反之ByteBuf转换为Java类型在Netty体系当中称之为Netty的解码。
前边我们讲到的各种的Encoder和Decoder解决的都是这样的问题。剩余的通信问题都是Netty帮我们做了,我们只需要关注于自定义边编解码就可以了。
在这里插入图片描述

现在假设我们想要将“10-20”这样的数据编码成Long类型的数据,然后通过Netty发送给服务端。站在我们的服务端我们接收过来的数据是ByteBuf我们想要把他解码成Long类型。以上情况就涉及到编解码过程。显然,这个功能Netty是没有给我们提供的,我们基于此开发一个编码器和一个解码器。

我们现在想对任何一个框架进行一下拓展,都需要使用当前框架提供的规范进行开发。这个规范指的就是框架提供各种各种的接口或者父类。我们遵循这些规范即可,框架自身也会遵循这些规范。

作为编码器来讲,他需要继承一个父类:MessageToByteEncoder,解码器需要继承一个父类:ByteToMessageDecoder,最后将我们开发的边解码器假如到客户端或者服务端的pipeLine当中。

我们这里边发送的是要给字符串,创建一个类MyLongToByteEncoder extends MessageToByteEncoder去继承这个类之后,我们实现encoder方法,这个ctx是整个pileLine的上线文,是整个PipeLine的一个核心实现,获得了ctx就等于拿到了这个channel当中的pipeLine中的所有信息。这个ctx当中都有啥,channel和ByteBuf以及各种各样的Handler。msg带表了,客户端client要输出的内容,对于我们这个案例来讲我们在这里输出的就是10-20的数据。第三个参数ByteBufout就代表了就真正的往服务端写数据的ByteBuf,我们转换好的数据好存放到这里边。

我们基于循环的方式将每一个Long类型的数据发送出去。这样我们的客户端就发送出去了。这里有写以为,我们之前不都是使用一个内部类吗?为什么这里不用匿名内部类了。为什么现在不用了,首先从设计的角度来讲,我们要尽可能的少使用这个内部类,因为内部类的重用性很差,所以一个类型要复用话,我们尽量不用内部类,除非这个类的使用范围仅限于本类,这个时候我们才会考虑使用内部类,这是一种变量的封装。最典型的内部类体现封装概念的案例就是Map.Entry<key,value> 实际上做内部类就不是一个地道的方式,后续开发过程中要少用内部类。

服务器端,我们先使用一个LongHandler进行解码,将ByteBuf转换为Long(一个Long在ByteBuf当中占用8个字节)然后添加一个自定义的解码器,将数据存存储到这里边。所以这个List的泛型是Object

客户端代码:

public class MyNettyClient {
    public static void main(String[] args) throws InterruptedException{
        log.debug("myNettyClientStarter------");
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        Bootstrap group = bootstrap.group(eventLoopGroup);
        bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel ch) throws Exception {
                ch.pipeline().addLast(new LoggingHandler());
                //自定义编码器
                //Encoderxxx
                ch.pipeline().addLast(new MyLongToByteEncoder());
                //编解码器 或者 handler 匿名的内部类 重用性差
                //内部类 ---> 使用范围 仅限于本类 (封装) Map  Map.Entry(key -- value)
            }
        });
        Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel();
        channel.writeAndFlush("10-20");

    }
}

public class MyLongToByteEncoder extends MessageToByteEncoder<String>{

    private static final Logger log = LoggerFactory.getLogger(MyLongToByteEncoder.class);

    @Override
    //获得了ctx等于拿到了这个channel相关的pipeline中的所有信息
    //1. channel
    //2. ByteBuf
    // String msg 编码器接受的 client输出的内容
    //ByteBuf out 真正往服务端写的ByteBuf的数据,细节  xxx
    protected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception {
        log.debug("encode method invoke  ");
        String[] messges = msg.split("-");
        for (String messge : messges) {
            long resultLong = Long.parseLong(messge);
            //每一个long类型的数据,在bytebuf中占用8个字节
            out.writeLong(resultLong);
        }
    }
}

客户端日志:

2022-11-24 22:24:46.048 [nioEventLoopGroup-2-1] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.checkBounds: true
2022-11-24 22:24:46.049 [nioEventLoopGroup-2-1] DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@2ac301e9
2022-11-24 22:24:46.052 [nioEventLoopGroup-2-1] DEBUG com.suns.netty10.MyLongToByteEncoder - encode method invoke  
2022-11-24 22:24:46.054 [nioEventLoopGroup-2-1] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0x3c44ede1, L:/192.168.1.4:53328 - R:0.0.0.0/0.0.0.0:8000] WRITE: 16B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 14 |................|
+--------+-------------------------------------------------+----------------+
2022-11-24 22:24:46.054 [nioEventLoopGroup-2-1] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0x3c44ede1, L:/192.168.1.4:53328 - R:0.0.0.0/0.0.0.0:8000] FLUSH

服务端代码:

public class MyNettyServer {
    public static void main(String[] args) {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.channel(NioServerSocketChannel.class);
        serverBootstrap.group(new NioEventLoopGroup());
        serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            //
            protected void initChannel(NioSocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new LoggingHandler());
                //ByteBuf --- Long
                //解码过程
                pipeline.addLast(new MyByteToLongDecoder());
                //pipeline.addLast(new MyLongCodec());
                pipeline.addLast(new ChannelInboundHandlerAdapter(){
                    @Override
                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                          log.debug("recive date in handler ...");
                          if(msg instanceof Long){
                              Long result = (Long) msg;
                              log.debug("my handler data is {} ",result);
                          }
                    }
                });
            }
        });
        //
        serverBootstrap.bind(8000);
    }
}

public class MyByteToLongDecoder extends ByteToMessageDecoder {
    @Override
    //获得了ctx等于拿到了这个channel相关的pipeline中的所有信息
    //1. channel
    //2. ByteBuf
    //ByteBuf in client提交上来的数据
    // decode方法处理的过程中,如果bytebuf没有处理完,那么他会重复调用decode方法
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        log.debug("decode method invoke ...");//ssss
        if (in.readableBytes() >= 8) {
            in.markReaderIndex();
                long reciveLong = in.readLong();
                out.add(reciveLong);
        }
        System.out.println(ByteBufUtil.prettyHexDump(in));
    }
}

服务端日志:

2022-11-24 22:24:46.064 [nioEventLoopGroup-2-2] DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@53fb3f15
2022-11-24 22:24:46.067 [nioEventLoopGroup-2-2] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0x57544fbc, L:/192.168.1.4:8000 - R:/192.168.1.4:53328] READ: 16B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 14 |................|
+--------+-------------------------------------------------+----------------+
2022-11-24 22:24:46.073 [nioEventLoopGroup-2-2] DEBUG com.suns.netty10.MyByteToLongDecoder - decode method invoke ...
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 00 00 00 00 14                         |........        |
+--------+-------------------------------------------------+----------------+
2022-11-24 22:24:46.074 [nioEventLoopGroup-2-2] DEBUG com.suns.netty10.MyNettyServer - recive date in handler ...
2022-11-24 22:24:46.074 [nioEventLoopGroup-2-2] DEBUG com.suns.netty10.MyNettyServer - my handler data is 10 
2022-11-24 22:24:46.074 [nioEventLoopGroup-2-2] DEBUG com.suns.netty10.MyByteToLongDecoder - decode method invoke ...

2022-11-24 22:24:46.074 [nioEventLoopGroup-2-2] DEBUG com.suns.netty10.MyNettyServer - recive date in handler ...
2022-11-24 22:24:46.074 [nioEventLoopGroup-2-2] DEBUG com.suns.netty10.MyNettyServer - my handler data is 20 

站在客户端角度来讲,客户端是使用一次给我们发送过来的,16个字节一次给发过来的。但是为什么站在服务端解码的时候要调用两个decode方法,产生了两个Message。(整个PipeLine的调用次数是按照Message个数定义的)但是消息我认可是两个,但是为啥要decode方法两次呢?这个是在Netty体系当中一个很大的坑,如果在Netty当中的ByteBuf当中如果一次性没处理完。他就会再次调用decode方法。再次交给你处理,恰好此时我们的数据时候16个字节,我们这就取了8个字节,这个时候我们的就调用了两次,如果是20个字节,我们的decode方法被调用了三次,这个是以处理完没处理完ByteBuf当中的数据当做一回事的。readLong读了8个字节,后边还有8个字节。
decode方法外部包了一层循环,只要是我们的ByteBuf当中还有数据没有读完。就会重复的调用decode方法,接着去处理。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Facial_Mask/article/details/127991656

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签