【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 {
    @Override
    protected 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. 创建一个通道初始化对象
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                //8. 向pipeline中添加自定义业务处理handler
                socketChannel.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> {

    @Override
    protected 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() {
        @Override
        public 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. 创建一个通道初始化对象
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                //6. 向pipeline中添加自定义业务处理handler
                socketChannel.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 {
    @Override
    protected 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));
    }

    @Override
    protected 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. 创建一个通道初始化对象
            @Override
            protected 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. 创建一个通道初始化对象
            @Override
            protected 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());
            }
        });

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

本地无法连接注册中心eureka,如何进行feign调用,并快速启动本地调试?

前言 今年进入了个新公司&#xff0c;接手代码时遇到了比较蛋疼的事情&#xff0c;本地代码调试遇到了层层阻碍&#xff0c;无法一键简单启动就算了&#xff0c;我就忍了&#xff0c;一番操作终于启动起了了&#xff0c;启动又慢&#xff0c;启动了2~3分钟&#xff0c;后面调本…

【音视频】remb twcc原理

目录 twcc简介 WebRTC REMB 参考文档 twcc简介 TWCC全称是Transport wide Congestion Control&#xff0c;是webrtc的最新的拥塞控制算法。其原理是在接收端保存数据包状态&#xff0c;然后构造RTCP包反馈给发送端&#xff0c;反馈信息包括包到达时间、丢包状态等&#xff…

养老院自助饮水机(字符设备驱动)

目录 1、项目背景 2、驱动程序 2.1 三层架构 2.2 驱动三要素 2.3 字符设备驱动 2.3.1 驱动模块 2.3.2 应用层 3、设计实现 3.1 项目设计 3.2 项目实现 3.2.1 驱动模块代码 3.2.2 用户层代码 4、功能特性 5、技术分析 6. 总结与未来展望 1、项目背景 养老院的老人…

社交网络分析(汇总)

这里写自定义目录标题 写在最前面社交网络分析系列文章汇总目录 提纲问题一、社交网络相关定义和概念提纲问题1. 社交网络、社交网络分析&#xff1b;2. 六度分隔理论、贝肯数、顿巴数&#xff1b;3. 网络中的数学方法&#xff1a;马尔科夫过程和马尔科夫链、平均场理论、自组织…

仿悬赏猫任务平台源码 悬赏任务系统源码 带支付接口

源码介绍 最新仿悬赏猫任务平台源码 悬赏任务系统源码 带支付接口&#xff0c; 全新开发悬赏任务系统&#xff0c;功能齐全&#xff0c;包含接任务&#xff0c;发布任务&#xff0c; 店铺关注&#xff0c;置顶推荐&#xff0c;排行榜&#xff0c;红包大厅&#xff0c;红包抽奖…

Android Studio如何实现 成语接龙游戏(简单易上手)

该项目是一个基于Android Studio和Java语言编写的成语接龙游戏App。成语接龙是一种经典的中文文字游戏&#xff0c;旨在测试玩家的词汇量和思维敏捷性。该成语接龙游戏App旨在提供一种有趣、挑战性和教育性的游戏体验。玩家可以通过游戏提高自己的中文词汇量和思维敏捷性&#…

Text Intelligence - TextIn.com AI时代下的智能文档识别、处理、转换

本指南将介绍Text Intelligence&#xff0c;AI时代下的智能文档技术平台 Textin.com 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0c;复旦机器人智能实验室成员&#xff0c;阿里云认…

KubeSphere应用【六】中间件部署

一、Mysql部署 1.1创建配置字典 [client] default-character-setutf8mb4 [mysql] default-character-setutf8mb4[mysqld] sql_modeSTRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION init_connectSET…

【分治算法】之汉诺塔问题

汉诺塔问题 三根柱子 把A柱子上的盘子全部挪到C上&#xff0c;且每次挪动的时候 小的必须在大的上面 分治算法的思想; 分&#xff1a;把一个大问题拆成若干个小的子问题&#xff0c;每个子问题相互独立&#xff1b; 治&#xff1a;求解每个子问题的&#xff08;递归&#xf…

前端FLV视频直播解决方案

项目背景&#xff1a; 1. 后台给出一个地址&#xff0c;持续不断的推送flv视频流。 2.前端需要接收视频流&#xff0c;并寻找合适的播放插件。 一开始&#xff1a; 其实用的是xgplayer&#xff08;西瓜视频&#xff09;。 官网地址&#xff1a;西瓜播放器 使用的是直播&a…

开放式耳机怎么选?2023高人气品牌推荐:新手避坑必看!

自从开放式耳机风靡市场以来&#xff0c;大家对于开放式耳机的选购也越发摸不着头脑。价格从百元到千元不等&#xff0c;就连大品牌的产品口碑也褒贬不一。 不少人私信向我询问&#xff1a; 1、难道只有千元价位的开放式耳机才好吗&#xff1f;2、是否有价格更实惠且性价比更…

如何使用 Helm 在 K8s 上集成 Prometheus 和 Grafana|Part 1

本系列将分成三个部分&#xff0c;您将学习如何使用 Helm 在 Kubernetes 上集成 Prometheus 和 Grafana&#xff0c;以及如何在 Grafana 上创建一个简单的控制面板。Prometheus 和 Grafana 是 Kubernetes 最受欢迎的两种开源监控工具。学习如何使用 Helm 集成这两个工具&#x…

C#电源串口调试

目的 记录串口调试的遇到的一些问题以及相应的解决方法 1.串口定义:串口是计算机与其他硬件传输数据的通道&#xff0c;在计算机与外设通信时起到重要作用 2.串口通信的基础知识 C#中的串口通信类 C#使用串口通信类是SerialPort(),该类使用方法是 new 一个 SerialPort对象 为S…

Prometheus-JVM

一. JVM监控 通过 jmx_exporter 启动端口来实现JVM的监控 Github Kubernetes Deployment Java 服务&#xff0c;修改 wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.19.0/jmx_prometheus_javaagent-0.19.0.jar# 编写配置文件&#xff0…

JAVA判断两个时间之间的差

1.首先引入jar包 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.7</version> </dependency>2.计算差值 public static DateFormat getDateTimeFormat(){DateFormat dtf new Sim…

即将来临的2024年,汽车战场再起波澜?

我们来简要概况一下11月主流车企的销量表现&#xff1a; 根据数据显示&#xff0c;11月吉利集团总销量29.32万辆&#xff0c;同比增长28%。这在当月国内主流车企中综合实力凌厉&#xff0c;可谓表现得体。而与吉利直接竞争的比亚迪&#xff0c;尽管数据未公布&#xff0c;但我们…

华为二层交换机与防火墙配置实例

二层交换机与防火墙对接上网配置示例 组网图形 图1 二层交换机与防火墙对接上网组网图 二层交换机简介配置注意事项组网需求配置思路操作步骤配置文件相关信息 二层交换机简介 二层交换机指的是仅能够进行二层转发&#xff0c;不能进行三层转发的交换机。也就是说仅支持二层…

Flink系列之:Savepoints

Flink系列之&#xff1a;Savepoints 一、Savepoints二、分配算子ID三、Savepoint 状态四、算子五、触发Savepoint六、Savepoint 格式七、触发 Savepoint八、使用 YARN 触发 Savepoint九、使用 Savepoint 停止作业十、从 Savepoint 恢复十一、跳过无法映射的状态恢复十二、Resto…

22 3GPP在SHF频段基于中继的5G高速列车场景中的标准化

文章目录 信道模型实验μ参考信号初始接入方法波形比较 RRH&#xff1a;remote radio head 远程无线头 HTS&#xff1a;high speed train 高速移动列车 信道模型 考虑搭配RRH和车载中继站之间的LOS路径以及各种环境&#xff08;开放或峡谷&#xff09;&#xff0c;在本次实验场…

Postgresql源码(118)elog/ereport报错跳转功能分析

1 日志接口 elog.c完成PG中日志的生产、记录工作&#xff0c;对外常用接口如下&#xff1a; 1.1 最常用的ereport和elog ereport(ERROR,(errcode(ERRCODE_UNDEFINED_TABLE),errmsg("relation \"%s\" does not exist",relation->relname)));elog(ERRO…