Introduction

UDT is a very good protocol that can provide high-speed data transmission based on the UDP protocol. But unfortunately in netty 4.1.7, the UDT transport protocol has been marked as Deprecated!

Means that in later versions of netty, you may never see the UDT protocol again.

How can an excellent protocol be buried, let's lift the veil of UDT, show its excellent features, and let netty love UDT again.

Netty support for UDT

Netty's support for UDT is reflected in a special UDT package to deal with UDT-related things: package io.netty.channel.udt.

This package mainly defines various channels of UDT, channel configuration, UDT message and tool class NioUdtProvider that provides ChannelFactory and SelectorProvider.

Build a netty service that supports UDT

According to the standard process of netty, it is time to create a netty service.

Netty's creation of a server service is nothing more than creating EventLoop, creating ServerBootstrap, binding EventLoop, and specifying the channel type. It's very simple.

The only difference is the specific childHandler, which may use different processing methods according to the specific protocol.

Of course, if it is not NioSocketChannel, then the corresponding ChannelFactory and SelectorProvider will also change.

It doesn't matter, let's first see how to create a netty service that supports UDT:

 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();

It can be seen that the difference between UDT and ordinary netty socket service is that its selector and channelFactory are provided by NioUdtProvider.

NioUdtProvider is the content of the netty core package. It provides a useful encapsulation of UDT. We don't need to know much about the internal implementation of UDT to use the UDT protocol. Isn't it wonderful.

Anomaly strikes

If a small partner is eager to take the above code to try to run, then unfortunately you will get an exception, the exception is probably similar to the following:

包com.barchart.udt找不到!

What? Directly using the class in the netty package will report an error? Tolerable or unbearable!

Let's analyze it carefully. There is only one new class here, which is NioUdtProvider. Open the source code of NioUdtProvider, and in the import column, we are surprised to find that packages that do not belong to netty are referenced, and it is these packages that report errors:

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;

Although it is very strange, we still need to find these dependency packages if we want the program to run. After my own journey through mountains and rivers, and over mountains and mountains, I finally worked hard. The following dependency packages were found:

<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>

The netty core package actually depends on third-party libraries, which may be the reason why netty is going to remove UDT support.

TypeUDT and KindUDT

If you look at the specific information of the class in barchart, you will find that the author of this package has a habit of putting a UDT behind the class.

When you see that all the classes on the screen end with UDT, yes, it is the barchart package that netty UDT depends on.

We can't say that the package developed by the big cows is not good, but that it looks a little tired....

There are two core classes in the barchart package that are used to distinguish UDT type and kind, namely TypeUDT and KindUDT.

It seems that there is not much difference between Type and kind translated into Chinese. But the two are still very different in UDT.

TypeUDT represents the mode of the UDT socket. It has two values, stream and datagram:

    STREAM(1),
    DATAGRAM(2),

Indicates whether the data transmission is in the form of a byte stream or in the form of a data packet message.

KindUDT is used to distinguish whether it is server-side or client-side. It has three modes:

ACCEPTOR,
CONNECTOR,
RENDEZVOUS

The server mode corresponds to ACCEPTOR, which is used to monitor and receive connections. Its representative is ServerSocketChannelUDT, which returns a CONNECTOR by calling the accept() method.

The CONNECTOR mode can be used on both the client and server sides, and its representative class is SocketChannelUDT.

If it is on the server side, it is generated by calling the accept method on the server side. If it is on the client side, it represents the connection between the client side and the server side.

Another mode is the RENDEZVOUS mode. This pattern means that each side of the connection has symmetric peer channels. That is, a bidirectional mode, and its representative class is RendezvousChannelUDT.

Build ChannelFactory

The two Types and the three Kinds mentioned above are used to define channels, so if they are mixed, six different channelFactory will be generated, which are:

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);

These channelFactory generate new channels by calling the newChannel() method.

But at the root, these channels finally call the from method of SelectorProviderUDT to generate channels.

SelectorProviderUDT

There are two types of SelectorProviderUDT according to TypeUDT, they are:

public static final SelectorProviderUDT DATAGRAM = 
    new SelectorProviderUDT(TypeUDT.DATAGRAM);

    public static final SelectorProviderUDT STREAM = 
    new SelectorProviderUDT(TypeUDT.STREAM);

The corresponding channel can be generated by calling his three methods:

    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);
    }

Using UDTs

After setting up the netty server, the rest is to write Handler to process the data.

Here we simply write back the data written by the client. The client first creates a message:

message = Unpooled.buffer(UDTEchoClient.SIZE);
 message.writeBytes("www.flydean.com".getBytes(StandardCharsets.UTF_8));

Then write to the server side:

    public void channelActive(final ChannelHandlerContext ctx) {
        log.info("channel active " + NioUdtProvider.socketUDT(ctx.channel()).toStringOptions());
        ctx.writeAndFlush(message);
    }

The server receives through the channelRead method:

public void channelRead(final ChannelHandlerContext ctx, Object msg) {
        ctx.write(msg);
    }

Summarize

The above is the principle and a simple example of using UDT in netty.

Examples of this article can be found in: learn-netty4

This article has been included in http://www.flydean.com/40-netty-udt-support/

The most popular interpretation, the most profound dry goods, the most concise tutorials, and many tricks you don't know are waiting for you to discover!

Welcome to pay attention to my official account: "Program those things", understand technology, understand you better!


flydean
890 声望433 粉丝

欢迎访问我的个人网站:www.flydean.com