【Netty】编解码器

2023-12-22 19:12
文章标签 netty 编解码器

本文主要是介绍【Netty】编解码器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • Java的编解码
  • Netty编解码器
    • 概念
    • 解码器(Decoder)
    • 编码器(Encoder)
    • 编码解码器Codec

Java的编解码

编码(Encode)称为序列化, 它将对象序列化为字节数组,用于网络传输、数据持久化或者其它用途。

解码(Decode)称为反序列化,它把从网络、磁盘等读取的字节数组还原成原始对象(通常是原始对象的拷贝),以方便后续的业务逻辑操作。

在这里插入图片描述

java序列化对象只需要实现java.io.Serializable接口并生成序列化ID,这个类就能够通过java.io.ObjectInput和java.io.ObjectOutput序列化和反序列化。

Java序列化目的:1.网络传输。2.对象持久化。

Java序列化缺点:1.无法跨语言。 2.序列化后码流太大。3.序列化性能太低。

Java序列化仅仅是Java编解码技术的一种,由于它的种种缺陷,衍生出了多种编解码技术和框架,这些编解码框架实现消息的高效序列化。

Netty编解码器

概念

在网络应用中需要实现某种编解码器,将原始字节数据与自定义的消息对象进行互相转换。网络中都是以字节码的数据形式来传输数据的,服务器编码数据后发送到客户端,客户端需要对数据进行解码。

对于Netty而言,编解码器由两部分组成:编码器、解码器。

  • 解码器:负责将消息从字节或其他序列形式转成指定的消息对象。
  • 编码器:将消息对象转成字节或其他序列形式在网络上传输。

Netty 的编(解)码器实现了 ChannelHandlerAdapter,也是一种特殊的 ChannelHandler,所以依赖于 ChannelPipeline,可以将多个编(解)码器链接在一起,以实现复杂的转换逻辑。

解码器负责处理“入站 InboundHandler”数据。 编码器负责“出站OutboundHandler” 数据。

解码器(Decoder)

解码器负责解码“入站”数据从一种格式到另一种格式,解码器处理入站数据是抽象ChannelInboundHandler的实现。需要将解码器放在ChannelPipeline中。对于解码器,Netty中主要提供了抽象基类ByteToMessageDecoderMessageToMessageDecoder

在这里插入图片描述

抽象解码器

  • ByteToMessageDecoder: 用于将字节转为消息,需要检查缓冲区是否有足够的字节
  • ReplayingDecoder: 继承ByteToMessageDecoder,不需要检查缓冲区是否有足够的字节,但是 ReplayingDecoder速度略慢于ByteToMessageDecoder,同时不是所有的ByteBuf都支持。项目复杂性高则使用ReplayingDecoder,否则使用ByteToMessageDecoder
  • MessageToMessageDecoder: 用于从一种消息解码为另外一种消息(例如POJO到POJO)

核心方法:

decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out)

示例:

在入门案例的代码基础上进行改造

  1. 解码器

添加解码器

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.CharsetUtil;import java.nio.ByteBuffer;
import java.util.List;public class MessageDecoder extends MessageToMessageDecoder {@Overrideprotected void decode(ChannelHandlerContext channelHandlerContext, Object o, List list) throws Exception {System.out.println("正在进行消息解码....");ByteBuffer byteBuffer = (ByteBuffer) o;list.add(byteBuffer.toString());}
}
  1. 通道读取方法

修改NettyServerHandler的通道读取事件,不需要我们手动解码了,直接读取即可,代码如下:r

/*** 通道读取事件** @param channelHandlerContext* @param o* @throws Exception*/
@Override
public void channelRead(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {System.out.println("客户端发送过来的消息:" + o);
}

对应的客户端的NettyClientHandler的通道读就绪事件也修改:

/*** 通道读就绪事件** @param channelHandlerContext* @param o* @throws Exception*/
@Override
public void channelRead(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {System.out.println("服务端发送的消息:" + o);
}
  1. 启动类

向pipeline中添加自定义业务处理handler时,把解码器添加进去,注意添加顺序,解码器要放在第一个,以服务端为例,代码如下:

serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) //5. 设置服务端通道实现为NIO.option(ChannelOption.SO_BACKLOG, 128) //6. 参数设置:初始化服务器可连接队列大小.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE) //6. 参数设置: 一直保持连接活动状态.childHandler(new ChannelInitializer<SocketChannel>() { //7. 创建一个通道初始化对象@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {//8. 向pipeline中添加自定义业务处理handlersocketChannel.pipeline().addLast(new MessageDecoder()); //添加解码器socketChannel.pipeline().addLast(new NettyServerHandler());}});

客户端也添加即可。

编码器(Encoder)

Netty提供了对应的编码器实现MessageToByteEncoderMessageToMessageEncoder,二者都实现ChannelOutboundHandler接口。

在这里插入图片描述

抽象编码器:

  • MessageToByteEncoder: 将消息转化成字节
  • MessageToMessageEncoder: 用于从一种消息编码为另外一种消息(例如POJO到POJO)

核心方法:

encode(ChannelHandlerContext ctx, String msg, List<Object> out)

示例:

  1. 编码器

新加编码器:

package com.cys.netty.codec;import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.CharsetUtil;import java.util.List;public class MessageEncoder extends MessageToMessageEncoder<String> {@Overrideprotected void encode(ChannelHandlerContext channelHandlerContext, String s, List<Object> list) throws Exception {System.out.println("消息进行消息编码");list.add(Unpooled.copiedBuffer(s, CharsetUtil.UTF_8));}
}
  1. 消息发送

修改NettyServerHandler里的通道读取完毕事件,直接发送数据,无序再编码,代码如下:

/*** 通道读取完毕事件** @param channelHandlerContext* @throws Exception*/
@Override
public void channelReadComplete(ChannelHandlerContext channelHandlerContext) throws Exception {// 消息出站channelHandlerContext.writeAndFlush("你好.我是Netty服务端");
}

同样修改NettyClientHandler里的通道就绪事件方法,直接发送数据,无序再编码,代码如下:

/*** 通道就绪事件** @param channelHandlerContext* @throws Exception*/
@Override
public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {ChannelFuture future = channelHandlerContext.writeAndFlush("你好呀.我是Netty客户端");future.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture channelFuture) throws Exception {if (channelFuture.isSuccess()) {System.out.println("数据发送成功!");} else {System.out.println("数据发送失败!");}}});
}
  1. 启动类

向pipeline中添加自定义业务处理handler,添加解码器和编码器,以客户端为例,代码如下:

bootstrap.group(group).channel(NioSocketChannel.class) //4. 设置客户端通道实现为NIO.handler(new ChannelInitializer<SocketChannel>() { //5. 创建一个通道初始化对象@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {//6. 向pipeline中添加自定义业务处理handlersocketChannel.pipeline().addLast(new MessageDecoder()); //添加解码器socketChannel.pipeline().addLast(new MessageEncoder());  //添加编码器socketChannel.pipeline().addLast(new NettyClientHandler());}});

同时服务端也可以加即可。

编码解码器Codec

编码解码器: 同时具有编码与解码功能,特点同时实现了ChannelInboundHandler和ChannelOutboundHandler接口,因此在数据输入和输出时都能进行处理。

在这里插入图片描述

Netty提供提供了一个ChannelDuplexHandler适配器类,编码解码器的抽象基类ByteToMessageCodec ,MessageToMessageCodec都继承与此类。

示例:

  1. 编解码器

新加编解码器,继承MessageToMessageCodec,代码如下:

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.util.CharsetUtil;import java.util.List;public class MessageCoder extends MessageToMessageCodec {@Overrideprotected void encode(ChannelHandlerContext channelHandlerContext, Object o, List list) throws Exception {System.out.println("正在进行消息编码");String str = (String) o;list.add(Unpooled.copiedBuffer(str, CharsetUtil.UTF_8));}@Overrideprotected void decode(ChannelHandlerContext channelHandlerContext, Object o, List list) throws Exception {System.out.println("正在进行消息解码");ByteBuf byteBuf = (ByteBuf) o;list.add(byteBuf.toString(CharsetUtil.UTF_8));}
}
  1. 启动类

向pipeline中添加自定义业务处理handler,只添加上面一个编解码器即可:

服务端:

serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) //5. 设置服务端通道实现为NIO.option(ChannelOption.SO_BACKLOG, 128) //6. 参数设置:初始化服务器可连接队列大小.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE) //6. 参数设置: 一直保持连接活动状态.childHandler(new ChannelInitializer<SocketChannel>() { //7. 创建一个通道初始化对象@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {//8. 向pipeline中添加自定义业务处理handler// socketChannel.pipeline().addLast(new MessageDecoder()); //添加解码器// socketChannel.pipeline().addLast(new MessageEncoder());  //添加编码器socketChannel.pipeline().addLast(new MessageCoder());  //添加编解码器socketChannel.pipeline().addLast(new NettyServerHandler());}});

客户端:

bootstrap.group(group).channel(NioSocketChannel.class) //4. 设置客户端通道实现为NIO.handler(new ChannelInitializer<SocketChannel>() { //5. 创建一个通道初始化对象@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {//6. 向pipeline中添加自定义业务处理handler// socketChannel.pipeline().addLast(new MessageDecoder()); //添加解码器// socketChannel.pipeline().addLast(new MessageEncoder());  //添加编码器socketChannel.pipeline().addLast(new MessageCoder());  //添加编解码器socketChannel.pipeline().addLast(new NettyClientHandler());}});

这篇关于【Netty】编解码器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/525144

相关文章

【Netty】netty中都是用了哪些设计模式

对于工程师来说,掌握并理解运用设计模式,是非常重要的,但是除了学习基本的概念之外,需要结合优秀的中间件、框架源码学习其中的优秀软件设计,这样才能以不变应万变。 单例模式 单例模式解决的对象的唯一性,一般来说就是构造方法私有化、然后提供一个静态的方法获取实例。 在netty中,select用于处理CONTINUE、SELECT、BUSY_WAIT 三种策略,通过DefaultSelectStra

Java语言的Netty框架+云快充协议1.5+充电桩系统+新能源汽车充电桩系统源码

介绍 云快充协议+云快充1.5协议+云快充1.6+云快充协议开源代码+云快充底层协议+云快充桩直连+桩直连协议+充电桩协议+云快充源码 软件架构 1、提供云快充底层桩直连协议,版本为云快充1.5,对于没有对接过充电桩系统的开发者尤为合适; 2、包含:启动充电、结束充电、充电中实时数据获取、报文解析、Netty通讯框架、包解析工具、调试器模拟器软件等; 源码合作 提供完整云快充协议源代码

Netty源码解析9-ChannelHandler实例之MessageToByteEncoder

MessageToByteEncoder框架可见用户使用POJO对象编码为字节数据存储到ByteBuf。用户只需定义自己的编码方法encode()即可。 首先看类签名: public abstract class MessageToByteEncoder<I> extends ChannelOutboundHandlerAdapter 可知该类只处理出站事件,切确的说是write事件

Netty源码解析8-ChannelHandler实例之CodecHandler

编解码处理器作为Netty编程时必备的ChannelHandler,每个应用都必不可少。Netty作为网络应用框架,在网络上的各个应用之间不断进行数据交互。而网络数据交换的基本单位是字节,所以需要将本应用的POJO对象编码为字节数据发送到其他应用,或者将收到的其他应用的字节数据解码为本应用可使用的POJO对象。这一部分,又和JAVA中的序列化和反序列化对应。幸运的是,有很多其他的开源工具(prot

Netty源码解析7-ChannelHandler实例之TimeoutHandler

请戳GitHub原文: https://github.com/wangzhiwubigdata/God-Of-BigData TimeoutHandler 在开发TCP服务时,一个常见的需求便是使用心跳保活客户端。而Netty自带的三个超时处理器IdleStateHandler,ReadTimeoutHandler和WriteTimeoutHandler可完美满足此需求。其中IdleSt

Netty源码解析6-ChannelHandler实例之LoggingHandler

LoggingHandler 日志处理器LoggingHandler是使用Netty进行开发时的好帮手,它可以对入站\出站事件进行日志记录,从而方便我们进行问题排查。首先看类签名: @Sharablepublic class LoggingHandler extends ChannelDuplexHandler 注解Sharable说明LoggingHandler没有状态相关变量,

Netty源码解析5-ChannelHandler

ChannelHandler并不处理事件,而由其子类代为处理:ChannelInboundHandler拦截和处理入站事件,ChannelOutboundHandler拦截和处理出站事件。ChannelHandler和ChannelHandlerContext通过组合或继承的方式关联到一起成对使用。事件通过ChannelHandlerContext主动调用如fireXXX()和write(msg)

Netty源码解析4-Handler综述

Netty中的Handler简介 Handler在Netty中,占据着非常重要的地位。Handler与Servlet中的filter很像,通过Handler可以完成通讯报文的解码编码、拦截指定的报文、 统一对日志错误进行处理、统一对请求进行计数、控制Handler执行与否。一句话,没有它做不到的只有你想不到的 Netty中的所有handler都实现自ChannelHandler接口。按照输入

Netty源码解析3-Pipeline

请戳GitHub原文: https://github.com/wangzhiwubigdata/God-Of-BigData Channel实现概览 在Netty里,Channel是通讯的载体,而ChannelHandler负责Channel中的逻辑处理。 那么ChannelPipeline是什么呢?我觉得可以理解为ChannelHandler的容器:一个Channel包含一个Chan

Netty源码解析2-Reactor

请戳GitHub原文: https://github.com/wangzhiwubigdata/God-Of-BigData 更多文章关注:多线程/集合/分布式/Netty/NIO/RPC Java高级特性增强-集合Java高级特性增强-多线程Java高级特性增强-SynchronizedJava高级特性增强-volatileJava高级特性增强-并发集合框架Java高级特性增强-