Flutter开发App的未来及其在各行业的应用潜力分析
1067
2023-01-13
详解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
2.2 代码实现
MessageDecoder
package com.my.codec;
import io-ty.buffer.ByteBuf;
import io-ty.channel.ChannelHandlerContext;
import io-ty.handler.codec.MessageToMessageDecoder;
import io-ty.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
2.4 代码实现
MessageEncoder
package com.my.codec;
import io-ty.buffer.Unpooled;
import io-ty.channel.ChannelHandlerContext;
import io-ty.handler.codec.MessageToMessageEncoder;
import io-ty.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-ty.buffer.ByteBuf;
import io-ty.buffer.Unpooled;
import io-ty.channel.ChannelHandlerContext;
import io-ty.handler.codec.MessageToMessageCodec;
import io-ty.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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~