网易首页 > 网易号 > 正文 申请入驻

netty系列之:protobuf在UDP协议中的使用

0
分享至

简介

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的定义:

public class DatagramPacket
extends DefaultAddressedEnvelope implements ByteBufHolder

DatagramPacket继承自DefaultAddressedEnvelope,并且实现了ByteBufHolder接口。

其中的ByteBuf是数据包中需要传输的数据,InetSocketAddress是数据包需要发送到的地址。

而这个DefaultAddressedEnvelope又是继承自AddressedEnvelope:

public class DefaultAddressedEnvelope implements AddressedEnvelope

DefaultAddressedEnvelopee中有三个属性,分别是message,sender和recipient:

private final M message;
private final A sender;
private final A recipient;

这三个属性分别代表了要发送的消息,发送方的地址和接收方的地址。

DatagramPacketEncoder

DatagramPacketEncoder是一个DatagramPacket的编码器,所以要编码的对象就是DatagramPacket。上一节我们也提到了DatagramPacket实际上继承自AddressedEnvelope。所有的DatagramPacket都是一个AddressedEnvelope对象,所以为了通用起见,DatagramPacketEncoder接受的要编码的对象是AddressedEnvelope。

我们先来看下DatagramPacketEncoder的定义:

public class DatagramPacketEncoder extends MessageToMessageEncoder> {

DatagramPacketEncoder是一个MessageToMessageEncoder,它接受一个AddressedEnvelope的泛型,也就是我们要encoder的对象类型。

那么DatagramPacketEncoder会将AddressedEnvelope编码成什么呢?

DatagramPacketEncoder中定义了一个encoder,这个encoder可以在DatagramPacketEncoder初始化的时候传入:

private final MessageToMessageEncoder encoder;

public DatagramPacketEncoder(MessageToMessageEncoder encoder) {
this.encoder = checkNotNull(encoder, "encoder");
}

实际上DatagramPacketEncoder中实现的encode方法,底层就是调用encoder的encode方法,我们来看下他的实现:

protected void encode(
ChannelHandlerContext ctx, AddressedEnvelope msg, List out) throws Exception {
assert out.isEmpty();

encoder.encode(ctx, msg.content(), out);
if (out.size() != 1) {
throw new EncoderException(
StringUtil.simpleClassName(encoder) + " must produce only one message.");
}
Object content = out.get(0);
if (content instanceof ByteBuf) {
// Replace the ByteBuf with a DatagramPacket.
out.set(0, new DatagramPacket((ByteBuf) content, msg.recipient(), msg.sender()));
} else {
throw new EncoderException(
StringUtil.simpleClassName(encoder) + " must produce only ByteBuf.");
}
}

上面的逻辑就是从AddressedEnvelope中调用msg.content()方法拿到AddressedEnvelope中的内容,然后调用encoder的encode方法将其编码并写入到out中。

最后调用out的get方法拿出编码之后的内容,再封装到DatagramPacket中去。

所以不管encoder最后返回的是什么对象,最后都会被封装到DatagramPacket中,并返回。

总结一下,DatagramPacketEncoder传入一个AddressedEnvelope对象,调用encoder将AddressedEnvelope的内容进行编码,最后封装成为一个DatagramPacket并返回。

鉴于protoBuf的优异对象序列化能力,我们可以将ProtobufEncoder传入到DatagramPacketEncoder中,做为真实的encoder:

ChannelPipeline pipeline = ...;
pipeline.addLast("udpEncoder", new DatagramPacketEncoder(new ProtobufEncoder(...));

这样就把ProtobufEncoder和DatagramPacketEncoder结合起来了。

DatagramPacketDecoder

DatagramPacketDecoder是和DatagramPacketEncoder相反的操作,它是将接受到的DatagramPacket对象进行解码,至于解码成为什么对象,也是由传入其中的decoder属性来决定的:

public class DatagramPacketDecoder extends MessageToMessageDecoder {

private final MessageToMessageDecoder decoder;

public DatagramPacketDecoder(MessageToMessageDecoder decoder) {
this.decoder = checkNotNull(decoder, "decoder");
}

DatagramPacketDecoder要解码的对象是DatagramPacket,而传入的decoder要解码的对象是ByteBuf。

所以我们需要一个能够解码ByteBuf的decoder实现,而和protoBuf对应的就是ProtobufDecoder。

先来看下DatagramPacketDecoder的decoder方法是怎么实现的:

protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List out) throws Exception {
decoder.decode(ctx, msg.content(), out);

可以看到DatagramPacketDecoder的decoder方法很简单,就是从DatagramPacket中拿到content内容,然后交由decoder去decode。

如果使用ProtobufDecoder作为内置的decoder,则可以将ByteBuf对象decode成为ProtoBuf对象,刚好和之前讲过的encode相呼应。

将ProtobufDecoder传入DatagramPacketDecoder也非常简单,我们可以这样做:

ChannelPipeline pipeline = ...;
pipeline.addLast("udpDecoder", new DatagramPacketDecoder(new ProtobufDecoder(...));

这样一个DatagramPacketDecoder就完成了。

总结

可以看到,如果直接使用DatagramPacketEncoder和DatagramPacketDecoder加上ProtoBufEncoder和ProtoBufDecoder,那么实现的是DatagramPacket和ByteBuf直接的互相转换。

当然这里的ProtoBufEncoder和ProtoBufDecoder可以按照用户的需要被替换成为不同的编码解码器。

可以自由组合编码解码方式,就是netty编码器的最大魅力。

本文已收录于 http://www.flydean.com/17-1-netty-protobuf-udp/


特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
评南阳男童死亡:很多国家消灭了狂犬病,我们的狂犬疫苗主要打给了人

评南阳男童死亡:很多国家消灭了狂犬病,我们的狂犬疫苗主要打给了人

金水路7号站
2024-05-19 07:55:54
2天8个瓜,四字顶流塌房,黄晓明疑似恋爱,关晓彤被罚,出轨离婚

2天8个瓜,四字顶流塌房,黄晓明疑似恋爱,关晓彤被罚,出轨离婚

兮说戏说
2022-05-27 22:56:54
2年2亚!连续2年英超遭曼城逆转枪手众将精疲力尽&哈弗茨流泪

2年2亚!连续2年英超遭曼城逆转枪手众将精疲力尽&哈弗茨流泪

直播吧
2024-05-20 01:08:43
广东要下30天暴雨?气象部门回应

广东要下30天暴雨?气象部门回应

鲁中晨报
2024-05-19 09:31:03
滕哈格:就算只能踢欧协联,曼联对每个球员来说都很有吸引力

滕哈格:就算只能踢欧协联,曼联对每个球员来说都很有吸引力

懂球帝
2024-05-19 08:04:14
不香了吗?从每天6亿到每天22亿!俄央行再次加大抛售人民币力度

不香了吗?从每天6亿到每天22亿!俄央行再次加大抛售人民币力度

云姐闲聊
2024-05-19 11:42:48
已达740元/克!有人没买金饰“肠子悔青”:买了一堆施华洛世奇,现在回收也没人要

已达740元/克!有人没买金饰“肠子悔青”:买了一堆施华洛世奇,现在回收也没人要

每日经济新闻
2024-05-19 13:31:09
史上最佳!瓜帅封神:英超4连冠+15年12夺联赛冠军,缔造5大神迹

史上最佳!瓜帅封神:英超4连冠+15年12夺联赛冠军,缔造5大神迹

侃球熊弟
2024-05-20 00:51:10
徐冬冬大量走光照被贩卖!怒批:我拍是我的事,敢卖我一定告到底

徐冬冬大量走光照被贩卖!怒批:我拍是我的事,敢卖我一定告到底

薇薇说事儿
2024-05-19 14:57:05
蝉联亚军!90分钟绝杀,2-1,阿森纳豪取6连胜,仍痛失英超冠军

蝉联亚军!90分钟绝杀,2-1,阿森纳豪取6连胜,仍痛失英超冠军

侧身凌空斩
2024-05-20 01:03:26
你想怎么踢都行水晶宫的收官战对决,连续两赛季无关任何角逐

你想怎么踢都行水晶宫的收官战对决,连续两赛季无关任何角逐

直播吧
2024-05-19 11:48:25
9轮全胜轰33球瓜帅此前狂奶追不上枪手,收官62个净胜球追平

9轮全胜轰33球瓜帅此前狂奶追不上枪手,收官62个净胜球追平

直播吧
2024-05-20 01:51:30
滇红茶为什么比一般红茶耐泡?

滇红茶为什么比一般红茶耐泡?

华庭讲美食
2024-04-27 00:07:40
首付15%相当于6.7倍的杠杆,只要跌个15%就灰飞烟灭。

首付15%相当于6.7倍的杠杆,只要跌个15%就灰飞烟灭。

知秋侃史
2024-05-18 12:12:12
沉默两天后,白宫终于就普京访华发声,称对中俄关系发展感到不安

沉默两天后,白宫终于就普京访华发声,称对中俄关系发展感到不安

镇远校尉
2024-05-18 15:12:03
12秒80!吴艳妮日本两连冠!刷新个人赛季最佳+今年亚洲最好成绩

12秒80!吴艳妮日本两连冠!刷新个人赛季最佳+今年亚洲最好成绩

念洲
2024-05-19 14:54:46
38岁凤姐美国公园被偶遇,性格高傲不理人,月入5k生活拮据!

38岁凤姐美国公园被偶遇,性格高傲不理人,月入5k生活拮据!

古希腊掌管月桂的神
2024-05-18 08:34:33
全球5.3亿人疯了!全球首例糖尿病痊愈,将引发53万亿市场价值

全球5.3亿人疯了!全球首例糖尿病痊愈,将引发53万亿市场价值

简读视觉
2024-05-18 16:05:02
史上最差曼联!曼联连胜收官仍创英超最低排名,连刷5大尴尬纪录

史上最差曼联!曼联连胜收官仍创英超最低排名,连刷5大尴尬纪录

奥拜尔
2024-05-20 01:06:26
五大联赛冠军全部出炉!曼城7年夺6冠,称霸英超,3豪门各获2亚军

五大联赛冠军全部出炉!曼城7年夺6冠,称霸英超,3豪门各获2亚军

侃球熊弟
2024-05-20 00:52:10
2024-05-20 02:04:49
flydean程序那些事
flydean程序那些事
最通俗的解读,最深刻的干货!
356文章数 438关注度
往期回顾 全部

科技要闻

雷军直播开车2000万人围观!突然遭别车

头条要闻

载有伊朗总统的直升机发生硬着陆事故

头条要闻

载有伊朗总统的直升机发生硬着陆事故

体育要闻

克洛普最后一舞!安菲尔德巨大TIFO致敬

娱乐要闻

《庆余年2》首播口碑出炉!有好有坏

财经要闻

洞庭湖区非法采砂 2000余亩洲滩被挖空

汽车要闻

智驾升级/月底上市 问界新M7 MAX焕新版

态度原创

游戏
亲子
数码
时尚
公开课

梦幻西游214武神坛决赛:无底化生都扛不住,珍宝阁九黎蚩尤附体

亲子要闻

萌娃回家看电视不想写作业,被妈妈训了在爸爸面前“演戏卖惨”,“原来我们小时候的演技这么拙劣”

数码要闻

Machdyne 推出 Blaustahl U 盘:8KB FRAM、200 年寿命

去了成都才发现:太古里满街都是“吊带+低腰裤”,时髦又养眼

公开课

父亲年龄越大孩子越不聪明?

无障碍浏览 进入关怀版