亲宝软件园·资讯

展开

Netty编解码器 详解Netty编码器和解码器

_tommy 人气:2
想了解详解Netty编码器和解码器的相关内容吗,_tommy在本文为您仔细讲解Netty编解码器的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Netty编码器,Netty解码器,Java,Netty,下面大家一起来学习吧。

一、java的编解码

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

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

image-20210605230045944

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

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,可以将多个编(解)码器链接在一起,以实现复杂的转换逻辑。

Netty里面的编解码: 解码器:负责处理“入站 InboundHandler”数据。 编码器:负责“出站 OutboundHandler” 数据。

入栈解码,出栈编码:

2.1 解码器(Decoder)

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

image-20210605231024070

抽象解码器

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

ReplayingDecoder: 继承ByteToMessageDecoder,不需要检查缓冲区是否有足够的字节,但 是 ReplayingDecoder速度略慢于ByteToMessageDecoder,同时不是所有的ByteBuf都支持。 项目复杂性高则使用ReplayingDecoder,否则使用ByteToMessageDecoder

MessageToMessageDecoder: 用于从一种消息解码为另外一种消息(例如POJO到POJO)

核心方法

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

2.2 代码实现

 MessageDecoder

package com.my.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.CharsetUtil;

import java.util.List;

/**
 * 消息解码器
 */
public class MessageDecoder extends MessageToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, Object msg, List out) throws Exception {
        System.out.println("正在进行消息解码....");
        ByteBuf byteBuf = (ByteBuf) msg;
        out.add(byteBuf.toString(CharsetUtil.UTF_8));//传递到下一个handler
    }
}

NettyServerHandler

nettyServerHandler 实现ChannelInboundHandler, 重新若干方法。

通道读取方法:

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

服务端在接收客户端的消息时,首先会经过MessageDecoder编码器,将字节变为字符串,因此,在此处可直接输出。

NettyServer

serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
                .childHandler(new ChannelInitializer<SocketChannel>() { 
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        //添加解码器
                        ch.pipeline().addLast("messageDecoder", new MessageDecoder());
                        //向pipeline中添加自定义业务处理handler
                        ch.pipeline().addLast(new NettyServerHandler());
                    }
                });

在pipeline中添加解码器

2.3 编码器(Encoder)

与ByteToMessageDecoder和MessageToMessageDecoder相对应,Netty提供了对应的编码器 实现MessageToByteEncoder和MessageToMessageEncoder,二者都实现 ChannelOutboundHandler接口。

image-20210605232231876

抽象编码器

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

核心方法:

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

2.4 代码实现

MessageEncoder

package com.my.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 {
    @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));
    }
}

NettyClientHandler

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

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

当客户端通道准备就绪时,会向服务端发送 “你好呀.我是Netty客户端”,由于出栈是逆序的,因此,直接传入字符串,当出栈时,会经过编码器(在nettyclient中添加的)

NettyClient

bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() { 
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        //添加解码器
                        ch.pipeline().addLast("messageDecoder", new MessageDecoder());
                        //添加编码器
                        ch.pipeline().addLast("messageEncoder", new MessageEncoder());                  
                        //向pipeline中添加自定义业务处理handler
                        ch.pipeline().addLast(new NettyClientHandler());
                    }
                });

同时,在NettyServerHandler 中也添加相同的编解码器。

因为是双向通信,因此,在服务端和客户端的pipeline中均需要添加编解码器。

2.5 测试结果

服务端打印:

image-20210605233932707

客户端打印:

image-20210605233943017

三、编码解码器Codec

编码解码器:

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

image-20210605234135527

Netty提供提供了一个ChannelDuplexHandler适配器类,编码解码器的抽象基类

ByteToMessageCodec ,MessageToMessageCodec都继承与此类

3.1 代码实现:

package com.my.codec;

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 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;
        out.add(byteBuf.toString(CharsetUtil.UTF_8));//传递到下一个handler
    }
}

NettyServer、NettyClient

在NettyServer和NettyClient中添加

ch.pipeline().addLast(new MessageCodec());
//8. 向pipeline中添加自定义业务处理handler
ch.pipeline().addLast(new NettyServerHandler());

eBuf = (ByteBuf) msg;
out.add(byteBuf.toString(CharsetUtil.UTF_8));//传递到下一个handler
}
}

ch.pipeline().addLast(new MessageCodec());
//8. 向pipeline中添加自定义业务处理handler
ch.pipeline().addLast(new NettyServerHandler());

测试结果与1.2.5测试结果一致

加载全部内容

相关教程
猜你喜欢
用户评论