簡介
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
本文已收錄於 http://www.flydean.com/40-netty-udt-support-2/
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!