详解Netty编码器和解码器

网友投稿 495 2022-10-21


详解Netty编码器和解码器

一、java的编解码

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

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

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。

抽象解码器

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

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

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

核心方法

decode(ChannelHandlerContext ctx, ByteBuf msg, List 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));//传递到下一个hpvYlteandler

}

}

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() {

@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接口。

抽象编码器

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

核心方法:

encode(ChannelHandlerContext ctx, String msg, List 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() {

@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 测试结果

服务端打印:

客户端打印:

三、编码解码器Codec

编码解码器:

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

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.cpvYlteopiedBuffer(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测试结果一致


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:工业级以太网交换机具有哪些优越特性
下一篇:安防专用交换机的应用介绍
相关文章

 发表评论

暂时没有评论,来抢沙发吧~