远方的灯塔 - 专注于服务端技术分享 远方的灯塔 - 专注于服务端技术分享
首页
  • Java SE
  • Struts2
  • Hibernate
  • MyBatis
  • JAX-WS
  • 并发
  • 分布式
  • Git
  • 文章分类
  • 文章标签
  • 文章归档
  • 《C程序设计语言》
心情随笔
友情链接
给我留言 (opens new window)
关于我
GitHub (opens new window)

Terwer Green

一个后端老菜鸟
首页
  • Java SE
  • Struts2
  • Hibernate
  • MyBatis
  • JAX-WS
  • 并发
  • 分布式
  • Git
  • 文章分类
  • 文章标签
  • 文章归档
  • 《C程序设计语言》
心情随笔
友情链接
给我留言 (opens new window)
关于我
GitHub (opens new window)
  • JavaSE

  • 开源框架

  • Linux

  • Struts2

  • Hibernate

  • Webservice

  • 分布式

    • RPC架构设计及IO模型
    • NIO编程及其三大核心原理
    • NIO三大核心之缓冲区(Buffer)
    • NIO三大核心之通道(Channel)
    • NIO三大核心之选择器(Selector)
    • Netty核心原理
    • 线程模型以及传统IO阻塞模型
    • Reactor模型
    • Netty线程模型
    • Netty核心API介绍
    • Netty入门与异步模型
    • Netty高级进阶之Netty编解码器
      • netty高级
        • Netty编解码器
        • Java的编解码
        • Netty编解码器
        • 概念
        • 解码器(Decoder)
        • 编码器(Encoder)
        • 编码解码器(Codec)
    • Netty高级进阶之基于Netty的群聊天室案例
    • Netty高级进阶之基于Netty的HTTP服务器开发
    • Netty高级进阶之基于Netty的Websocket开发网页聊天室
    • Netty高级进阶之Netty中的粘包和拆包的解决方案
    • Nety源码剖析
    • 自定义RPC框架之分布式架构网络通信理论
    • 自定义RPC框架之基于Netty实现RPC框架
    • 分布式架构理论
    • 分布式理论之数据一致性
    • 分布式理论之CAP定理
    • 分布式理论之BASE定理
    • 分布式一致性协议之两阶段提交协议(2PC)
    • 分布式一致性协议之三阶段提交协议(3PC)
    • 分布式一致性协议之NWR协议
    • 分布式一致性协议之Gossip协议
    • 分布式一致性协议之Paxos协议
    • 分布式一致性协议之Raft协议
    • 分布式一致性协议之Lease机制
    • 分布式系统设计策略之心跳检测
    • 分布式系统设计策略之高可用
    • 分布式系统设计策略之容错性
    • 分布式系统设计策略之负载均衡
    • 分布式架构服务调用
    • 分布式服务治理之服务协调
    • 分布式服务治理之服务削峰
    • 分布式服务治理之服务降级
    • 分布式服务治理之服务限流
    • 分布式服务治理之服务熔断
    • 分布式服务治理之服务链路追踪
    • 架构设计基本原则之开闭原则(OCP)
    • 架构设计基本原则之单一职责原则(SRP)
    • 架构设计基本原则之接口隔离原则(ISP)
    • 架构设计基本原则之里式替换原则(LSP)
    • 架构设计基本原则之依赖倒置原则(DIP)
    • 架构设计基本原则知识扩展
    • 分布式架构知识拓展与总结
  • 分布式框架

  • 后端开发
  • 分布式
terwer
2022-04-21
目录

Netty高级进阶之Netty编解码器

本文介绍了Netty编解码器的继承体系、常用API以及实际应用。

# netty高级

# Netty编解码器

# Java的编解码

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

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

    image-20220423190741342

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

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

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

    Java序列化仅仅是Java编解码技术的一种,由于它的缺陷,衍生出了很多编解码框架,这些框架可以实现信息的搞笑序列化。

# Netty编解码器

# 概念

网络应用需要实现某种编解码器,将原始字节数据与自定义消息之间进行转换。

网络中是以字节码的形式进行传输的,服务器编码数据之后发送到客户端,客户端需要对数据进行解码。

对Netty来说,编解码器分为两部分:编码器和解码器。

Netty的编解码器实现了 ChannelHandlerAdaptor ,他是一种特殊的 ChannelHandler ,依赖于 ChannelPipline,可以将多个编解码器连接在一起,实现复杂的转换逻辑。

Nertty的编解码

解码器:负责处理入站InboundHandler数据从一种格式到另一种格式。

编码器:负责处理出站OuboundHandler数据

# 解码器(Decoder)

解码器负责入站数据,解码器处理入站数据是ChannelInboundHandler的实现。需要将解码器放在ChannelPipline中。

对于解码器,Netty中提供了抽象基类 ByteToMessageDecoder 和 MessageToMessageDecoder。

classDiagram
direction BT
class ChannelHandler {
<<Interface>>

}
class ChannelHandlerAdapter
class ChannelInboundHandler {
<<Interface>>

}
class ChannelInboundHandlerAdapter
class MessageToMessageDecoder~I~
class HttpServerCodec
class ByteToMessageDecoder
class ReplayingDecoder~S~
class StringDecoder

ChannelHandlerAdapter  ..>  ChannelHandler 
ChannelInboundHandler  -->  ChannelHandler 
ChannelInboundHandlerAdapter  -->  ChannelHandlerAdapter 
ChannelInboundHandlerAdapter  ..>  ChannelInboundHandler 

MessageToMessageDecoder~I~  -->  ChannelInboundHandlerAdapter 
HttpServerCodec  ..>  ChannelHandler 
HttpServerCodec  -->  ChannelInboundHandlerAdapter 
ByteToMessageDecoder  -->  ChannelInboundHandlerAdapter 
StringDecoder  -->  MessageToMessageDecoder~I~ 
ReplayingDecoder~S~  -->  ByteToMessageDecoder 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

如果图片无法显示,请看这里

image-20220425200951629

  • 抽象解码器

    • ByteToMessageDecoder:用于将字节转为消息,需要检测缓冲区是否有足够的字节

    • ReplayingDecoder:继承自ByteToMessageDecoder,不需要检测缓冲区是否有足够的字节,但是ReplayingDecoder的速度略慢于ByteToMessageDecoder,而且并不是所有的ByteBuf都支持。

      项目复杂度高用ReplayingDecoder,否则使用ByteToMessageDecoder。

    • MessageToMessageDecoder:从一种消息解码为另一种消息,例如POJO到POJO

  • 核心方法

    decode(ChannelhandlerContext ctx, ByteBuf msg, List<Object> out)
    
    1
  • 代码实现

    解码器:

    /**
     * 消息解码器
     *
     * @name: MessageDecoder
     * @author: terwer
     * @date: 2022-04-26 21:03
     **/
    public class MessageDecoder extends MessageToMessageDecoder {
        @Override
        protected void decode(ChannelHandlerContext ctx, Object msg, List out) throws Exception {
            System.out.println("正在进行消息解码");
            ByteBuf byteBuf = (ByteBuf)msg;
            // 传递到下一个handler
            out.add(byteBuf.toString(CharsetUtil.UTF_8));
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    通道方法实现:

        /**
         * 通道读取事件
         *
         * @param ctx
         * @param msg
         * @throws Exception
         */
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    //        ByteBuf byteBuf = (ByteBuf) msg;
    //        System.out.println("客户端发过来的消息:" + byteBuf.toString(CharsetUtil.UTF_8));
            System.out.println("客户端发过来的消息:" + msg);
        }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    启动类:

    // 添加解码器,要放在自定义解码器之前
    ch.pipeline().addLast("MessageDecoder", new MessageDecoder());
    // 8. 向pipeline中添加自定义业务处理handler
    ch.pipeline().addLast(new NettyServerHandler());
    
    1
    2
    3
    4

实现效果:

image-20220426211349610

# 编码器(Encoder)

与解码器对应,Netty也提供了对应的编码器MessageToByteEncoder和MessageToMessageEncoder,它们都实现了ChannelOutboundHandler。

继承关系如下:

classDiagram
direction BT
class ChannelHandler {
<<Interface>>

}
class ChannelHandlerAdapter
class ChannelOutboundHandler {
<<Interface>>

}
class ChannelOutboundHandlerAdapter
class MessageToByteEncoder~I~
class MessageToMessageEncoder~I~

ChannelHandlerAdapter  ..>  ChannelHandler 
ChannelOutboundHandler  -->  ChannelHandler 
ChannelOutboundHandlerAdapter  -->  ChannelHandlerAdapter 
ChannelOutboundHandlerAdapter  ..>  ChannelOutboundHandler 
MessageToByteEncoder~I~  -->  ChannelOutboundHandlerAdapter 
MessageToMessageEncoder~I~  -->  ChannelOutboundHandlerAdapter 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

如果图片无法显示,请看这里

image-20220426211958116

  • 抽象编码器

    • MessageToByteEncoder:将消息转化为字节

    • MessageToMessageEncoder:用于从一种消息编码为另外一种消息,例如从POJO到POJO

  • 核心方法

    encode(ChannelhandlerContext ctx, String msg, List<Object> out)
    
    1
  • 代码实现

    编码器:

    /**
     * 消息编码器
     *
     * @name: MessageEncoder
     * @author: terwer
     * @date: 2022-04-26 21:28
     **/
    public class MessageEncoder extends MessageToMessageEncoder {
    
        @Override
        protected void encode(ChannelHandlerContext ctx, Object msg, List out) throws Exception {
            System.out.println("消息正在编码");
            String str = (String) msg;
            out.add(Unpooled.copiedBuffer(str, CharsetUtil.UTF_8));
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    通道写入方法:

        /**
         * 通道读取完成事件
         *
         * @param ctx
         * @throws Exception
         */
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    //        ctx.writeAndFlush(Unpooled.copiedBuffer("你好,我是Netty服务端。", CharsetUtil.UTF_8));
            ctx.writeAndFlush("你好,我是Netty服务端。");
        }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    启动类:

    // 添加解码器,要放在自定义解码器之前
    ch.pipeline().addLast("MessageDecoder", new MessageDecoder());
    // 添加编码器
    ch.pipeline().addLast("MessageEncoder",new MessageEncoder());
    // 8. 向pipeline中添加自定义业务处理handler
    ch.pipeline().addLast(new NettyServerHandler());
    
    1
    2
    3
    4
    5
    6

    实现效果:

    image-20220426223922272

# 编码解码器(Codec)

编码解码器:同时具备编码和解码功能。

特点是同时实现了ChannelInboundHandler和ChannelOutboundHandler接口,在输入和输出时都能进行处理。

继承关系如下:

classDiagram
direction BT
class ByteToMessageCodec~I~
class ChannelDuplexHandler
class ChannelHandler {
<<Interface>>

}
class ChannelHandlerAdapter
class ChannelInboundHandler {
<<Interface>>

}
class ChannelInboundHandlerAdapter
class ChannelOutboundHandler {
<<Interface>>

}
class MessageToMessageCodec~INBOUND_IN, OUTBOUND_IN~

ByteToMessageCodec~I~  -->  ChannelDuplexHandler 
ChannelDuplexHandler  -->  ChannelInboundHandlerAdapter 
ChannelDuplexHandler  ..>  ChannelOutboundHandler 
ChannelHandlerAdapter  ..>  ChannelHandler 
ChannelInboundHandler  -->  ChannelHandler 
ChannelInboundHandlerAdapter  -->  ChannelHandlerAdapter 
ChannelInboundHandlerAdapter  ..>  ChannelInboundHandler 
ChannelOutboundHandler  -->  ChannelHandler 
MessageToMessageCodec~INBOUND_IN, OUTBOUND_IN~  -->  ChannelDuplexHandler 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

如果图片无法查看,请看这里

image-20220427013952540

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

  • 代码实现

编解码器:

/**
 * 编解码器
 *
 * @name: MessageCodec
 * @author: terwer
 * @date: 2022-04-27 01:58
 **/
public class MessageCodec extends MessageToMessageCodec {

    /**
     * 编码
     * @param ctx
     * @param msg
     * @param out
     * @throws Exception
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Object msg, List out) throws Exception {
        System.out.println("消息正在编码,使用编解码器");
        String str = (String) msg;
        out.add(Unpooled.copiedBuffer(str, CharsetUtil.UTF_8));
    }

    /**
     *
     * @param ctx
     * @param msg
     * @param out
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, Object msg, List out) throws Exception {
        System.out.println("正在进行消息解码,使用编解码器");
        ByteBuf byteBuf = (ByteBuf)msg;
        // 传递到下一个handler
        out.add(byteBuf.toString(CharsetUtil.UTF_8));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

启动类:

// // 添加解码器,要放在自定义解码器之前
// ch.pipeline().addLast("MessageDecoder", new MessageDecoder());
// // 添加编码器
// ch.pipeline().addLast("MessageEncoder",new MessageEncoder());
// 添加编解码器
ch.pipeline().addLast("MessageCodec", new MessageCodec());
// 8. 向pipeline中添加自定义业务处理handler
ch.pipeline().addLast(new NettyServerHandler());
1
2
3
4
5
6
7
8

运行效果:

image-20220427020348463

编辑 (opens new window)
#netty#codec
上次更新: 2023/02/22, 13:47:25
Netty入门与异步模型
Netty高级进阶之基于Netty的群聊天室案例

← Netty入门与异步模型 Netty高级进阶之基于Netty的群聊天室案例→

最近更新
01
解决css部分border被圆角切掉之后圆角的边框消失问题
03-18
02
使用TypeScript开发一个自定义的Node-js前端开发脚手架
03-08
03
Github-Actions使用release-please实现自动发版
03-06
更多文章>
Theme by Vdoing | Copyright © 2011-2023 Terwer Green | MIT License | 粤ICP备2022020721号-1 | 百度统计
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式