netty系列之:protobuf在UDP協議中的使用
一起養成寫作習慣!這是我參與「掘金日新計劃 · 4 月更文挑戰」的第21天,點選檢視活動詳情。
簡介
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<ByteBuf, InetSocketAddress> implements ByteBufHolder
DatagramPacket繼承自DefaultAddressedEnvelope,並且實現了ByteBufHolder介面。
其中的ByteBuf是資料包中需要傳輸的資料,InetSocketAddress是資料包需要傳送到的地址。
而這個DefaultAddressedEnvelope又是繼承自AddressedEnvelope:
public class DefaultAddressedEnvelope<M, A extends SocketAddress> implements AddressedEnvelope<M, A>
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<M> extends MessageToMessageEncoder<AddressedEnvelope<M, InetSocketAddress>> {
DatagramPacketEncoder是一個MessageToMessageEncoder,它接受一個AddressedEnvelope的泛型,也就是我們要encoder的物件型別。
那麼DatagramPacketEncoder會將AddressedEnvelope編碼成什麼呢?
DatagramPacketEncoder中定義了一個encoder,這個encoder可以在DatagramPacketEncoder初始化的時候傳入:
``` private final MessageToMessageEncoder<? super M> encoder;
public DatagramPacketEncoder(MessageToMessageEncoder<? super M> encoder) {
this.encoder = checkNotNull(encoder, "encoder");
}
```
實際上DatagramPacketEncoder中實現的encode方法,底層就是呼叫encoder的encode方法,我們來看下他的實現:
```
protected void encode(
ChannelHandlerContext ctx, AddressedEnvelope
```
public class DatagramPacketDecoder extends MessageToMessageDecoder
private final MessageToMessageDecoder<ByteBuf> decoder;
public DatagramPacketDecoder(MessageToMessageDecoder<ByteBuf> decoder) {
this.decoder = checkNotNull(decoder, "decoder");
}
```
DatagramPacketDecoder要解碼的物件是DatagramPacket,而傳入的decoder要解碼的物件是ByteBuf。
所以我們需要一個能夠解碼ByteBuf的decoder實現,而和protoBuf對應的就是ProtobufDecoder。
先來看下DatagramPacketDecoder的decoder方法是怎麼實現的:
protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List<Object> 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/
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!
- Spring Boot 3.0橫空出世,快來看看是不是該升級了
- 會用redis嗎?那還不快來了解下redis protocol
- flutter 系列之:flutter 中的 offstage
- flutter系列之:flutter中的Wrap
- flutter系列之:flutter中的IndexedStack
- flutter 系列之:flutter 中的 builder
- flutter系列之:flutter中常用的box
- flutter系列之:按比例縮放的AspectRatio和FractionallySizedBox
- flutter系列之:查詢裝置資訊的利器:MediaQuery
- flutter系列之:UI layout簡介
- flutter系列之:構建Widget的上下文環境BuildContext詳解
- flutter系列之:widgets,構成flutter的基石
- 密碼學系列之:ASN.1介面描述語言詳解
- 關於安全策略,開發者需要知道的那些事
- 密碼學系列之:線上證書狀態協議OCSP詳解
- netty系列之:kequeue傳輸協議詳解
- netty系列之:在netty中使用native傳輸協議
- netty系列之:在netty中實現執行緒和CPU繫結
- 密碼學系列之:PKI的證書格式表示X.509
- 網路協議之:memcached binary protocol詳解