数据在网络的传输都是以字节的形式,解码就是将字节转换为实际的数据类型,编码是将实际的数据类型转换为字节。对于netty来说,编解码工作就是交给编解码来完成的。
netty本身已经提供了大量的编解码可供应用程序开发直接使用。但是,netty也不可能考虑到所有可能的情况,因此它也提供了很灵活的方式让应用开发人员可自定义编解码。
在netty中,编码器encoder就是出站处理器,解码decoder就是入站处理器。因此,在使用编解码时,只需要将它们添加到ChannelPipeline中即可,但是要注意编解码添加的前后顺序。
下面介绍下如何自定义编解码。
解码
字节转Message
字节转换为Message(这边指的是Java的原生数据类型或者引用类型),有两种方式:继承ByteToMessageDecoder或者ReplayingDecoder,然后重写decode方法。
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in,
List<Object> out) throws Exception;
ctx是当前解码的上下文对象,in为字节数据的来源,将从ByteBuf获取的字节数据转换为实际的数据类型后添加到out中。
ByteToMessageDecoder
当继承的是ByteToMessageDecoder时,在要转换ByteBuf的字节时需要判断其所拥有的字节数据是否足够。比如:若要转成long类型的,由于long类型需要8个字节,因此需要先调用in.readableBytes()判断ByteBuf是否至少有8个字节。如下
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out){
if(msg.readableBytes() >= 8) {
Long l = msg.readLong();
out.add(l);
}
}
若是ByteBuf的字节数不够的话,其read索引不会改变,并且会等待更多的字节数据到达。
ReplayingDecoder
当继承的是ReplayingDecoder时,在转换ByteBuf的字节数据时,无需判断其所拥有的字节数是否足够。如,在上面的例子中,可以直接这样转换
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out){
out.add(in.readLong());
}
Message转Message
若要将一个Message类型转换为令一个Message类型,需要继承MessageToMessageDecoder<T>并重写decode方法,注意在继承的时候需要指定泛型的实际类型,因为netty需要知道你要转的数据类型是什么,而ByteToMessageDecoder没有泛型参数,因为已经确定要转的就是byte类型了。如下,将Long转换为String类型
@Override
protected void decode(ChannelHandlerContext ctx, Long msg, List<Object> out) {
out.add("长整型:" + String.valueOf(msg));
}
编码器
编码器与解码相反,将message类型转换为字节,在netty中,自定义编码器需要继承MessageToByteEncoder<T>,然后重写encode方法,这边的泛型指的是要将什么类型数据转换为byte类型。如,将String转为Byte
public class MyStringToByteEncoder extends MessageToByteEncoder<String> {
@Override
protected void encode(ChannelHandlerContext ctx, String msg,
ByteBuf out) throws Exception {
out.writeBytes(msg.getBytes());
}
}
作者:panmingjie
链接:https://www.jianshu.com/p/0e24200a2494
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。