java 自定义解码_netty自定义编解码

数据在网络的传输都是以字节的形式,解码就是将字节转换为实际的数据类型,编码是将实际的数据类型转换为字节。对于netty来说,编解码工作就是交给编解码来完成的。

netty本身已经提供了大量的编解码可供应用程序开发直接使用。但是,netty也不可能考虑到所有可能的情况,因此它也提供了很灵活的方式让应用开发人员可自定义编解码。

在netty中,编码器encoder就是出站处理器,解码decoder就是入站处理器。因此,在使用编解码时,只需要将它们添加到ChannelPipeline中即可,但是要注意编解码添加的前后顺序。

下面介绍下如何自定义编解码。

解码

字节转Message

字节转换为Message(这边指的是Java的原生数据类型或者引用类型),有两种方式:继承ByteToMessageDecoder或者ReplayingDecoder,然后重写decode方法。

protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in,

List 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 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 out){

out.add(in.readLong());

}

Message转Message

若要将一个Message类型转换为令一个Message类型,需要继承MessageToMessageDecoder并重写decode方法,注意在继承的时候需要指定泛型的实际类型,因为netty需要知道你要转的数据类型是什么,而ByteToMessageDecoder没有泛型参数,因为已经确定要转的就是byte类型了。如下,将Long转换为String类型

@Override

protected void decode(ChannelHandlerContext ctx, Long msg, List out) {

out.add("长整型:" + String.valueOf(msg));

}

编码器

编码器与解码相反,将message类型转换为字节,在netty中,自定义编码器需要继承MessageToByteEncoder,然后重写encode方法,这边的泛型指的是要将什么类型数据转换为byte类型。如,将String转为Byte

public class MyStringToByteEncoder extends MessageToByteEncoder {

@Override

protected void encode(ChannelHandlerContext ctx, String msg,

ByteBuf out) throws Exception {

out.writeBytes(msg.getBytes());

}

}

作者:panmingjie

链接:https://www.jianshu.com/p/0e24200a2494

來源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty框架提供了很多编码器和解码器,但有时候我们需要自定义编码器和解码器,以满足特定的业务需求。在Netty中,自定义编码器和解码器非常简单,只需要继承ByteToMessageDecoder或MessageToByteEncoder,并实现其中的抽象方法即可。 以下是一个自定义编码器的示例代码: ```java public class MyEncoder extends MessageToByteEncoder<MyMessage> { @Override protected void encode(ChannelHandlerContext ctx, MyMessage msg, ByteBuf out) throws Exception { byte[] data = msg.getData(); out.writeInt(data.length); out.writeBytes(data); } } ``` 在这个示例中,我们定义了一个名为MyEncoder的编码器,它继承自MessageToByteEncoder,并实现了encode方法。在encode方法中,我们首先获取消息的数据,然后将消息的数据长度写入到ByteBuf中,最后将消息的数据写入到ByteBuf中。 以下是一个自定义解码器的示例代码: ```java public class MyDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { if (in.readableBytes() < 4) { return; } int length = in.readInt(); if (in.readableBytes() < length) { in.resetReaderIndex(); return; } byte[] data = new byte[length]; in.readBytes(data); MyMessage message = new MyMessage(length, data); out.add(message); } } ``` 在这个示例中,我们定义了一个名为MyDecoder的解码器,它继承自ByteToMessageDecoder,并实现了decode方法。在decode方法中,我们首先判断ByteBuf中是否有足够的字节可读,如果不够则直接返回。然后从ByteBuf中读取消息的长度和数据,并将它们封装成MyMessage对象,加入到解码结果列表中。 在使用自定义编码器和解码器时,只需要将它们注册到ChannelPipeline中即可。以下是注册的示例代码: ```java ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast(new MyDecoder()); pipeline.addLast(new MyEncoder()); ``` 这样,在ChannelPipeline中的所有ChannelHandler都可以使用MyMessage对象,而无需关心它们与字节流的转换过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值