“This is the first day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

Introduction to the

We know that the foundation of NetTY is channels and selectors on top of channels, and of course as a NIO framework, channels and selectors are the foundation not only of NetTY but of all NIO implementations.

In the same way, we know that netty has many different protocols, and these protocols communicate over channels. Will different protocols use different channels and selectors?

With this question in mind, let’s dig into it.

Basic construction of Netty services

Netty can be divided into client side and server side. In fact, there is little difference in the construction of client side and server side. For the sake of simplicity, the server side construction in NetTY is studied as an example.

Take a look back at our original Netty server, which looks like this:

BossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new FirstServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture f = b.bind(port).sync(); // Bind the port and start receiving connections.Copy the code

There are two things to note: the ServerBootstrap group method and its channel method.

EventLoopGroup

Groups can be implemented in two ways, taking either one or two parameters. Parameters are EventLoopGroup, EventLoopGroup is mainly used to register the channel, for subsequent Selector for choice.

If one parameter is used, an EventLoopGroup processes acceptor and client events at the same time. If two parameters are used, the two are separated.

Of course, none of this is the focus of today’s lecture, which is about how the EventLoopGroup is built differently for different protocols.

EventLoopGroup itself is an interface, he has a lot of kinds of implementation, but in essence or two EventLoop: SingleThreadEventLoop and MultithreadEventLoopGroup.

That is, single-threaded EventLoop processing and multi-threaded EventLoop processing.

For example, NioEventLoopGroup is a single-threaded EventLoop.

NioEventLoopGroup usually uses a constructor with no arguments. NioEventLoopGroup can actually pass in ThreadFactory, the number of threads, SelectorProvider, and SelectStrategyFactory.

Netty provides only a SelectStrategyFactory implementation: DefaultSelectStrategyFactory.

And corresponding SelectorProvider, the default implementation is SelectorProvider provider (), we look at the concrete implementation of this method:

public static SelectorProvider provider() { synchronized (lock) { if (provider ! = null) return provider; return AccessController.doPrivileged( new PrivilegedAction<SelectorProvider>() { public SelectorProvider run() { if (loadProviderFromProperty()) return provider; if (loadProviderAsService()) return provider; provider = sun.nio.ch.DefaultSelectorProvider.create(); return provider; }}); }}Copy the code

You can see that by default, there are three ways to create a SelectorProvider.

The first is to find from the system property: Java nio. Channels. Spi. SelectorProvider:

String cn = System.getProperty("java.nio.channels.spi.SelectorProvider"); Class<? > c = Class.forName(cn, true, ClassLoader.getSystemClassLoader()); provider = (SelectorProvider)c.newInstance();Copy the code

If defined, an instance is created and returned.

If not, the service Loader will be loaded from “meta-INF /services/” :

    private static boolean loadProviderAsService() {

        ServiceLoader<SelectorProvider> sl =
            ServiceLoader.load(SelectorProvider.class,
                               ClassLoader.getSystemClassLoader());
        Iterator<SelectorProvider> i = sl.iterator();
Copy the code

If servie also didn’t find it, will use the default sun. Nio. Ch. DefaultSelectorProvider.

channel

By default, we use NioServerSocketChannel. It is actually created from the default SelectorProvider mentioned above.

private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
return DEFAULT_SELECTOR_PROVIDER.openServerSocketChannel();
Copy the code

So the channel you’re using has to match the selector.

We can use channels directly, or we can use channelFactories to generate channels from those factories.

If you want to use ChannelFactory, you can call the ChannelFactory method of ServerBootstrap.

Multiple builds

The basic Netty Server build is mentioned above. The corresponding protocol is the Socket protocol.

For UDP connection, the corresponding channel should be NioDatagramChannel, as follows:

EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioDatagramChannel.class)
             .option(ChannelOption.SO_BROADCAST, true)
             .handler(new UDPServerHandler());

            b.bind(PORT).sync().channel().closeFuture().await();
Copy the code

The EventLoopGroup can remain unchanged.

Netty uses sockets for communication, and sockets are based on TCP or UDP. Therefore, HTTP, HTTP2, and SOCKS are implemented in NetTY based on Socket connections.

So for HTTP or http2, a channel is also a NioServerSocketChannel.

You can see that only UDP is different. The UDT protocol based on UDP is also different. It is used as follows:

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()); }});Copy the code

UDT uses the BYTE_PROVIDER and BYTE_ACCEPTOR provided in NioUdtProvider as selectors and channelFactory, respectively.

The other channel

In addition to NioSocketChannel, there are EpollChannel, KQueueChannel, and SctpChannel, which are used for different protocols. We’ll cover this in more detail in a future article.

conclusion

Channels and selectors are the basis of Netty, and on this basis, Netty can be extended to all protocols based on TCP and UDP, which can be said to be very powerful.

This article is available at www.flydean.com/39-netty-se…

The most popular interpretation, the most profound dry goods, the most concise tutorial, many tips you didn’t know waiting for you to discover!

Welcome to pay attention to my public number: “procedures those things”, understand technology, more understand you!