netty 系列之:protobuf 在 UDP 协议中的使用
简介
netty 中提供的 protobuf 编码解码器可以让我们直接在 netty 中传递 protobuf 对象。同时 netty 也提供了支持 UDP 协议的 channel 叫做 NioDatagramChannel。如果直接使用 NioDatagramChannel,那么我们可以直接从 channel 中读写 UDP 对象:DatagramPacket。
但是 DatagramPacket 中封装的是 ByteBuf 对象,如果我们想要向 UDP channel 中写入对象,那么需要一个将对象转换成为 ByteBuf 的方法,很明显 netty 提供的 protobuf 编码解码器就是一个这样的方法。
那么可不可以将 NioDatagramChannel 和 ProtobufDecoder,ProtobufEncoder 相结合呢?
NioDatagramChannel 中 channel 读写的对象都是 DatagramPacket。而 ProtobufDecoder 与 ProtobufEncoder 是将 protoBuf 对象 MessageLiteOrBuilder 跟 ByteBuf 进行转换,所以两者是不能直接结合使用的。
怎么才能在 UDP 中使用 protobuf 呢?今天要向大家介绍 netty 专门为 UDP 创建的编码解码器 DatagramPacketEncoder 和 DatagramPacketDecoder。
UDP 在 netty 中的表示
UDP 的数据包在 netty 中是怎么表示呢?
netty 提供了一个类 DatagramPacket 来表示 UDP 的数据包。netty 中的 UDP channel 就是使用 DatagramPacket 来进行数据的传递。先看下 DatagramPacket 的定义:
DatagramPacket 继承自 DefaultAddressedEnvelope,并且实现了 ByteBufHolder 接口。
其中的 ByteBuf 是数据包中需要传输的数据,InetSocketAddress 是数据包需要发送到的地址。
而这个 DefaultAddressedEnvelope 又是继承自 AddressedEnvelope:
DefaultAddressedEnvelopee 中有三个属性,分别是 message,sender 和 recipient:
这三个属性分别代表了要发送的消息,发送方的地址和接收方的地址。
DatagramPacketEncoder
DatagramPacketEncoder 是一个 DatagramPacket 的编码器,所以要编码的对象就是 DatagramPacket。上一节我们也提到了 DatagramPacket 实际上继承自 AddressedEnvelope。所有的 DatagramPacket 都是一个 AddressedEnvelope 对象,所以为了通用起见,DatagramPacketEncoder 接受的要编码的对象是 AddressedEnvelope。
我们先来看下 DatagramPacketEncoder 的定义:
DatagramPacketEncoder 是一个 MessageToMessageEncoder,它接受一个 AddressedEnvelope 的泛型,也就是我们要 encoder 的对象类型。
那么 DatagramPacketEncoder 会将 AddressedEnvelope 编码成什么呢?
DatagramPacketEncoder 中定义了一个 encoder,这个 encoder 可以在 DatagramPacketEncoder 初始化的时候传入:
实际上 DatagramPacketEncoder 中实现的 encode 方法,底层就是调用 encoder 的 encode 方法,我们来看下他的实现:
上面的逻辑就是从 AddressedEnvelope 中调用msg.content()
方法拿到 AddressedEnvelope 中的内容,然后调用 encoder 的 encode 方法将其编码并写入到 out 中。
最后调用 out 的 get 方法拿出编码之后的内容,再封装到 DatagramPacket 中去。
所以不管 encoder 最后返回的是什么对象,最后都会被封装到 DatagramPacket 中,并返回。
总结一下,DatagramPacketEncoder 传入一个 AddressedEnvelope 对象,调用 encoder 将 AddressedEnvelope 的内容进行编码,最后封装成为一个 DatagramPacket 并返回。
鉴于 protoBuf 的优异对象序列化能力,我们可以将 ProtobufEncoder 传入到 DatagramPacketEncoder 中,做为真实的 encoder:
这样就把 ProtobufEncoder 和 DatagramPacketEncoder 结合起来了。
DatagramPacketDecoder
DatagramPacketDecoder 是和 DatagramPacketEncoder 相反的操作,它是将接受到的 DatagramPacket 对象进行解码,至于解码成为什么对象,也是由传入其中的 decoder 属性来决定的:
DatagramPacketDecoder 要解码的对象是 DatagramPacket,而传入的 decoder 要解码的对象是 ByteBuf。
所以我们需要一个能够解码 ByteBuf 的 decoder 实现,而和 protoBuf 对应的就是 ProtobufDecoder。
先来看下 DatagramPacketDecoder 的 decoder 方法是怎么实现的:
可以看到 DatagramPacketDecoder 的 decoder 方法很简单,就是从 DatagramPacket 中拿到 content 内容,然后交由 decoder 去 decode。
如果使用 ProtobufDecoder 作为内置的 decoder,则可以将 ByteBuf 对象 decode 成为 ProtoBuf 对象,刚好和之前讲过的 encode 相呼应。
将 ProtobufDecoder 传入 DatagramPacketDecoder 也非常简单,我们可以这样做:
这样一个 DatagramPacketDecoder 就完成了。
总结
可以看到,如果直接使用 DatagramPacketEncoder 和 DatagramPacketDecoder 加上 ProtoBufEncoder 和 ProtoBufDecoder,那么实现的是 DatagramPacket 和 ByteBuf 直接的互相转换。
当然这里的 ProtoBufEncoder 和 ProtoBufDecoder 可以按照用户的需要被替换成为不同的编码解码器。
可以自由组合编码解码方式,就是 netty 编码器的最大魅力。
本文已收录于 http://www.flydean.com/17-1-netty-protobuf-udp/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
版权声明: 本文为 InfoQ 作者【程序那些事】的原创文章。
原文链接:【http://xie.infoq.cn/article/4cc19dbc9286925c01907ee4e】。文章转载请联系作者。
评论