简介
UDT是一个十分优良的协定,能够提供在UDP协定根底上进行高速数据传输。然而惋惜的是在netty 4.1.7中,UDT传输协定曾经被标记为Deprecated了!
意味着在前面的netty版本中,你可能再也看不到UDT协定了.
优良的协定怎么可能被湮没,让咱们揭开UDT的面纱,展现其优良的个性,让netty再爱UDT一次吧。
netty对UDT的反对
netty对UDT的反对体现在有一个专门的UDT包来解决UDT相干事件:package io.netty.channel.udt。
这个包外面次要定义了UDT的各种channel、channel配置、UDT音讯和提供ChannelFactory和SelectorProvider的工具类NioUdtProvider.
搭建一个反对UDT的netty服务
依照netty的规范流程,当初是须要创立一个netty服务的时候了。
netty创立server服务无非就是创立EventLoop、创立ServerBootstrap、绑定EventLoop、指定channel类型就完了,十分的简略。
惟一不同的就是具体的childHandler,可能依据具体协定的不同应用不同的解决形式。
当然,如果不是NioSocketChannel,那么对应的ChannelFactory和SelectorProvider也会有所变动。
没关系,咱们先看下如何创立反对UDT的netty服务:
final ThreadFactory acceptFactory = new DefaultThreadFactory("accept"); final ThreadFactory connectFactory = new DefaultThreadFactory("connect"); final NioEventLoopGroup acceptGroup = new NioEventLoopGroup(1, acceptFactory, NioUdtProvider.BYTE_PROVIDER); final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, connectFactory, NioUdtProvider.BYTE_PROVIDER); 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 UDTEchoServerHandler()); } }); // 开启服务 final ChannelFuture future = boot.bind(PORT).sync();
能够看到,UDT和一般netty socket服务不同的中央在于它的selector和channelFactory都是由NioUdtProvider来提供了。
NioUdtProvider是netty外围包中的内容,他提供了对UDT的有用封装,咱们不须要要懂太多UDT外部的实现,就能够应用UDT协定,是不是很美好。
异样来袭
如果有小伙伴灰溜溜的拿下面这段代码去尝试运行,那么很惋惜你会失去异样,异样大略相似上面的状况:
包com.barchart.udt找不到!
什么?间接应用netty包中的类竟然会报错?是可忍孰不可忍!
咱们来仔细分析一下,这里只有一个新的类就是NioUdtProvider,关上NioUdtProvider的源码,在import一栏,咱们赫然发现竟然援用了不属于netty的包,就是这些包报错了:
import com.barchart.udt.SocketUDT;import com.barchart.udt.TypeUDT;import com.barchart.udt.nio.ChannelUDT;import com.barchart.udt.nio.KindUDT;import com.barchart.udt.nio.RendezvousChannelUDT;import com.barchart.udt.nio.SelectorProviderUDT;
尽管很诡异,然而咱们要想程序跑起来还是须要找出这些依赖包,通过自己的跋山涉水、跋山涉水终于功夫不负苦心人,上面的依赖包找到了:
<dependency> <groupId>com.barchart.udt</groupId> <artifactId>barchart-udt-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.barchart.udt</groupId> <artifactId>barchart-udt-bundle</artifactId> <version>2.3.0</version> </dependency>
netty外围包竟然要依赖与第三方库,这可能就是netty筹备删除对UDT反对的起因吧。
TypeUDT和KindUDT
如果你去查看barchart中类的具体信息,就会发现这个包的作者有个嗜好,喜爱把类前面带上一个UDT。
当你看到满屏的类都是以UDT结尾的时候,没错,它就是netty UDT依赖的包barchart本包了。
大牛们开发的包咱们不能说他不好,只能说看起来有点累....
barchart包中有两个比拟外围的用来辨别UDT type和kind的两个类,别离叫做TypeUDT和KindUDT.
Type和kind翻译成中文如同没太大区别。然而两者在UDT中还是有很大不同的。
TypeUDT示意的是UDT socket的模式。它有两个值,别离是stream和datagram:
STREAM(1), DATAGRAM(2),
示意数据传输是以字节流的模式还是以数据报文音讯的格局来进行传输。
KindUDT则用来辨别是服务器端还是客户端,它有三种模式:
ACCEPTOR,CONNECTOR,RENDEZVOUS
server模式对应的是ACCEPTOR,用来监听和接管连贯.它的代表是ServerSocketChannelUDT,通过调用accept()办法返回一个CONNECTOR.
CONNECTOR模式能够同时在客户端和服务器端应用,它的代表类是SocketChannelUDT.
如果是在server端,则是通过调用server端的accept办法生成的。如果是在客户端,则示意的是客户端和服务器端之间的连贯。
还有一种模式是RENDEZVOUS模式。这种模式示意的是连贯的每一侧都有对称对等的channel。也就是一个双向的模式,它的代表类是RendezvousChannelUDT。
构建ChannelFactory
下面提到的两种Type和三种Kind都是用来定义channel的,所以如果将其混合,会生成六种不同的channelFactory,别离是:
public static final ChannelFactory<UdtServerChannel> BYTE_ACCEPTOR = new NioUdtProvider<UdtServerChannel>( TypeUDT.STREAM, KindUDT.ACCEPTOR);public static final ChannelFactory<UdtChannel> BYTE_CONNECTOR = new NioUdtProvider<UdtChannel>( TypeUDT.STREAM, KindUDT.CONNECTOR);public static final ChannelFactory<UdtChannel> BYTE_RENDEZVOUS = new NioUdtProvider<UdtChannel>( TypeUDT.STREAM, KindUDT.RENDEZVOUS);public static final ChannelFactory<UdtServerChannel> MESSAGE_ACCEPTOR = new NioUdtProvider<UdtServerChannel>( TypeUDT.DATAGRAM, KindUDT.ACCEPTOR);public static final ChannelFactory<UdtChannel> MESSAGE_CONNECTOR = new NioUdtProvider<UdtChannel>( TypeUDT.DATAGRAM, KindUDT.CONNECTOR);public static final ChannelFactory<UdtChannel> MESSAGE_RENDEZVOUS = new NioUdtProvider<UdtChannel>( TypeUDT.DATAGRAM, KindUDT.RENDEZVOUS);
这些channelFactory通过调用newChannel()办法来生成新的channel。
然而归根节点,这些channel最初是调用SelectorProviderUDT的from办法来生成channel的。
SelectorProviderUDT
SelectorProviderUDT依据TypeUDT的不同有两种,别离是:
public static final SelectorProviderUDT DATAGRAM = new SelectorProviderUDT(TypeUDT.DATAGRAM); public static final SelectorProviderUDT STREAM = new SelectorProviderUDT(TypeUDT.STREAM);
能够通过调用他的三个办法来生成对应的channel:
public RendezvousChannelUDT openRendezvousChannel() throws IOException { final SocketUDT socketUDT = new SocketUDT(type); return new RendezvousChannelUDT(this, socketUDT); } public ServerSocketChannelUDT openServerSocketChannel() throws IOException { final SocketUDT serverSocketUDT = new SocketUDT(type); return new ServerSocketChannelUDT(this, serverSocketUDT); } public SocketChannelUDT openSocketChannel() throws IOException { final SocketUDT socketUDT = new SocketUDT(type); return new SocketChannelUDT(this, socketUDT); }
应用UDT
搭建好了netty服务器,剩下就是编写Handler对数据进行解决了。
这里咱们简略的将客户端写入的数据再回写。客户端先创立一个message:
message = Unpooled.buffer(UDTEchoClient.SIZE); message.writeBytes("www.flydean.com".getBytes(StandardCharsets.UTF_8));
再写入到server端:
public void channelActive(final ChannelHandlerContext ctx) { log.info("channel active " + NioUdtProvider.socketUDT(ctx.channel()).toStringOptions()); ctx.writeAndFlush(message); }
服务器端通过channelRead办法来接管:
public void channelRead(final ChannelHandlerContext ctx, Object msg) { ctx.write(msg); }
总结
以上就是netty中应用UDT的原理和一个简略的例子。
本文的例子能够参考:learn-netty4
本文已收录于 http://www.flydean.com/40-netty-udt-support/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!