netty系列之:選byte還是選message?這是一個問題
簡介
UDT給了你兩種選擇,byte stream或者message,到底選哪一種呢?經驗告訴我們,只有小學生才做選擇題,而我們應該全都要!
類型的定義
UDT的兩種類型是怎麼定義的呢?
翻看com.barchart.udt包,可以發現這兩種類型定義在TypeUDT枚舉類中。
STREAM(1),
DATAGRAM(2),
一個叫做STREAM,它的code是1。一個叫做DATAGRAM,他的code是2.
根據兩個不同的類型我們可以創建不同的selectorProvider和channelFactory。而這兩個正是構建netty服務所需要的。
在NioUdtProvider這個工具類中,netty為我們提供了TypeUDT和KindUDT的六種組合ChannelFactory,他們分別是:
用於Stream的:BYTE_ACCEPTOR,BYTE_CONNECTOR,BYTE_RENDEZVOUS。
和用於Message的:MESSAGE_ACCEPTOR,MESSAGE_CONNECTOR和MESSAGE_RENDEZVOUS。
同樣的,還有兩個對應的SelectorProvider,分別是:
BYTE_PROVIDER 和 MESSAGE_PROVIDER.
搭建UDT stream服務器
如果要搭建UDT stream服務器,首先需要使用NioUdtProvider.BYTE_PROVIDER來創建NioEventLoopGroup:
final NioEventLoopGroup acceptGroup = new NioEventLoopGroup(1, acceptFactory, NioUdtProvider.BYTE_PROVIDER);
final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, connectFactory, NioUdtProvider.BYTE_PROVIDER);
這裡,我們創建兩個eventLoop,分別是acceptLoop和connectLoop。
接下來就是在ServerBootstrap中綁定上面的兩個group,並且指定channelFactory。這裡我們需要NioUdtProvider.BYTE_ACCEPTOR:
final ServerBootstrap boot = new ServerBootstrap();
boot.group(acceptGroup, connectGroup)
.channelFactory(NioUdtProvider.BYTE_ACCEPTOR)
.option(ChannelOption.SO_BACKLOG, 10)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<UdtChannel>() {
@Override
public void initChannel(final UdtChannel ch) {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO),
new UDTByteEchoServerHandler());
}
});
就這麼簡單。
搭建UDT message服務器
搭建UDT message服務器的步驟和stream很類似,不同的是需要使用NioUdtProvider.MESSAGE_PROVIDER作為selectorProvider:
final NioEventLoopGroup acceptGroup =
new NioEventLoopGroup(1, acceptFactory, NioUdtProvider.MESSAGE_PROVIDER);
final NioEventLoopGroup connectGroup =
new NioEventLoopGroup(1, connectFactory, NioUdtProvider.MESSAGE_PROVIDER);
然後在綁定ServerBootstrap的時候使用NioUdtProvider.MESSAGE_ACCEPTOR作為channelFactory:
final ServerBootstrap boot = new ServerBootstrap();
boot.group(acceptGroup, connectGroup)
.channelFactory(NioUdtProvider.MESSAGE_ACCEPTOR)
.option(ChannelOption.SO_BACKLOG, 10)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<UdtChannel>() {
@Override
public void initChannel(final UdtChannel ch)
throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO),
new UDTMsgEchoServerHandler());
}
});
同樣很簡單。
Stream和Message的handler
不同的UDT類型,需要使用不同的handler。
對於Stream來說,它的底層是byte,所以我們的消息處理也是以byte的形式進行的,我們以下面的方式來構建message:
private final ByteBuf message;
message = Unpooled.buffer(UDTByteEchoClient.SIZE);
message.writeBytes("www.flydean.com".getBytes(StandardCharsets.UTF_8));
然後使用ctx.writeAndFlush(message)將其寫入到channel中。
對於message來說,它實際上格式對ByteBuf的封裝。netty中有個對應的類叫做UdtMessage:
public final class UdtMessage extends DefaultByteBufHolder
UdtMessage是一個ByteBufHolder,所以它實際上是一個ByteBuf的封裝。
我們需要將ByteBuf封裝成UdtMessage:
private final UdtMessage message;
final ByteBuf byteBuf = Unpooled.buffer(UDTMsgEchoClient.SIZE);
byteBuf.writeBytes("www.flydean.com".getBytes(StandardCharsets.UTF_8));
message = new UdtMessage(byteBuf);
然後將這個UdtMessage發送到channel中:
ctx.writeAndFlush(message);
這樣你就學會了在UDT協議中使用stream和message兩種數據類型了。
總結
大家可能覺得不同的數據類型原來實現起來這麼簡單。這全都要歸功於netty優秀的封裝和設計。
感謝netty!
本文的例子可以參考:learn-netty4
本文已收錄於 //www.flydean.com/40-netty-udt-support-2/
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!