乐趣区

关于java:netty系列之请netty再爱UDT一次

简介

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/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

退出移动版