First, Netty’s advantages

Despite our previous study NIO, simplify the code I have as much as possible, but we still found that the JDK NIO development still is a very complicated, we also have to take into account in the business development to the business process, the reuse of business, request the concurrency value, in the process of decoding, network transmission of packets of sticky problems, etc. Will further increase the difficulty of NIO development!

  • Netty is based on the above problems to provide a unified solution, Netty provides a unified template for Socket programming, even if a developer without network programming foundation, can also be very easy to develop a high concurrency, low latency program!

  • Netty provides many default codec functions, which can easily implement some common protocols in the market, such as FTP, HTTP, SMTP, WebSocket, etc., and can easily solve the problem of half packet and sticky packet in the process of network communication through a few lines of code.

  • Customized ability, Netty excellent code style and powerful extension ability, we can let the communication framework through ChannelHandler flexible extension, as well as through the pipeline flow (PipLine) to achieve mutual isolation and reuse of business functions!

  • Mature and stable, Netty has fixed all the JDK NIO bugs found in the JDK, the most famous of which is the infamous JDK empty train BUG!

  • Active community, short version iteration cycle, found bugs can be fixed in time, at the same time, more new features will be added;

Second, Netty architecture design

This is an architecture diagram from the official website, we can roughly understand the Netty module!

  • Core Core layer, is the main implementation of Netty, all subsequent extensions are built on Core, he provides the event extensible model, network communication programming universal API, data zero copy and data carrier encapsulation and reuse!
  • Netty provides the basic network communication capability, which abstracts the basic network communication protocols such as TCP and UDP, so that users are not bothered by the underlying technology of a network communication development, like attention can be more focused on business! It is this layer of encapsulation that allows seamless switching between NIO and BIO!
  • Protocol Support: Netty implements most of the mainstream protocols on the market, including HTTP, SSL, Protobuf, compression, large file transfer, WebSocket, text, binary, and other mainstream protocols. Netty also supports custom extended protocols. Netty’s rich protocol makes the user development cost greatly reduced, using the built-in protocol can be very easy to develop a similar to Tomcat Http server!

Three, the basic use and introduction of Netty

After the introduction of the above, we probably understand the basic architecture of Netty, we will look at the basic use of Netty, and then I will be line by line analysis, I hope to be able to help you through this class to start Netty programming, but also for the back of the source code to learn a better foundation!

1. Develop a server

We use Netty to develop a simple server-side code:

The server receives the message from the client, prints it, and actively disconnects!

Start server source code:

/** * server **@authorSource Apprentice@dateApril 19, 2021 12:39:21 */
public class EchoServer {

    public static void main(String[] args) {
        // Set the event loop group
        EventLoopGroup boss = new NioEventLoopGroup(1);
        EventLoopGroup worker = new NioEventLoopGroup();

        try {
            // Set the service initiator
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(8989)
                    // Set the service pipeline
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(newEchoServerHandler()); }});// Synchronously block until binding is complete
            ChannelFuture channelFuture = serverBootstrap.bind().sync();
            // Listen for the channel closing method and wait for the server channel closing to complete
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // Gracefully close the thread groupboss.shutdownGracefully(); worker.shutdownGracefully(); }}}Copy the code

The server reads the data handler source code: EchoServerHandler

/** * The server prints the handler **@author huangfu
 * @dateApril 19, 2021 12:42:34 */
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;
        try {
            // Convert to a string
            String message = byteBuf.toString(StandardCharsets.UTF_8);
            System.out.println(message);
        }finally{ ReferenceCountUtil.release(byteBuf); ctx.channel().close(); }}}Copy the code

2. Introduction to the server source code

EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
Copy the code

Define two groups of event loops. Remember our optimized version of NIO from Chapter 5? For now, you can think of it as two selector groups:

  • bossThere is only one selector selector inside that accepts new connections!
  • workerThe internal default isCPU*2Three selector selectors to process our business logic!

After receiving the new connection, the boss hands the SocketChannel generated by the new connection to the worker thread group for processing! To use a popular analogy, a boss is equivalent to a boss, while a worker is equivalent to a worker. A boss does not deal with work, but is only in charge of negotiating contracts. After receiving a new job, I give the work to the worker and take the next one myself!

These two lines of code are recommended to refer to the optimized version of NIO in the previous chapter!

ServerBootstrap serverBootstrap = new ServerBootstrap();
Copy the code

ServerBootstrap is a fast startup configuration class provided by Netty. The reason why Netty is easier to develop than NIO is that Netty provides us with a template of network programming code. If we want to use these templates, we must tell the template some necessary parameters for the template to read. During the initialization, we set various parameters and save them in the ServerBootstrap. Later, when the Netty service starts, it will read the parameters configured during the initialization and complete its initialization.

 serverBootstrap.group(boss, worker)
Copy the code

Bind the two event loop groups we initialized earlier and save them to serverBootstrap for later reading!

.channel(NioServerSocketChannel.class)
Copy the code

What we are developing here is a server program, so we are using NioServerSocketChannel, and there are two types of SocketChannel in Netty, one is NioServerSocketChannel and the other is NioSocketChannel, Both inherit the JDK’s ServerSocketChannel and SocketChannel, and are Netty’s official extensions to the communication channel:

  • NioServerSocketChannel: server channel
  • NioSocketChannel: client channel

There are two channels, we will analyze in detail later, here you first remember, NioServerSocketChannel represents the server channel! NioSocketChannel stands for client channel, don’t get confused!

.localAddress(8989)
Copy the code

Set a port number, the server exposed port number!

.childHandler(new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        socketChannel.pipeline().addLast(newEchoServerHandler()); }});Copy the code

We want to bind a channel to the client Socket and add our business processing class xxxxHandler. When a client is connected to the server, all subsequent business processing will be handled by various handlers registered here. This is the main logic provided by Netty to enable developers to focus on business development. We will focus on this piece of code later, but also remember that after we register these handlers, the data sent by the client will be processed in these handlers!

ChannelFuture channelFuture = serverBootstrap.bind().sync();
Copy the code

The initialization is complete, start to move to the server and port binding, binding according to the above Settings of port, the attentive students may find I still call a sync method, Netty is based on the asynchronous events to develop, here we bind call later, because be executed asynchronously, so we don’t know when to finish, So a blocking method (sync) is called and blocks until the binding is complete before proceeding!

channelFuture.channel().closeFuture().sync();
Copy the code

Get a server side channel object, and add a closed listener to the server side channel object, and call the blocking method (sync), after the call, the program will always block here, waiting for the server side channel closed, will continue to go down! Generally speaking, the server pipe will remain alive unless we actively shut down due to an abnormal crash, and the change will remain blocked here, forming a service!

boss.shutdownGracefully();
worker.shutdownGracefully();
Copy the code

Gracefully shutdown, the program will mark the channel as unavailable, waiting for the program to complete, release all resources created by Netty!

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {....}
Copy the code

When the server perceives the data sent from the client, it calls back this logic!

3. Develop a client

/** * print program client **@author huangfu
 * @dateApril 19, 2021 13:58:16 */
public class EchoClient {
    public static void main(String[] args) {
        EventLoopGroup worker = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.remoteAddress("127.0.0.1".8989)
                    .group(worker)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(newEchoClientHandler()); }}); ChannelFuture channelFuture = bootstrap.connect().sync(); channelFuture.channel().closeFuture().sync(); }catch (Exception e) {
            e.printStackTrace();
        } finally{ worker.shutdownGracefully(); }}}Copy the code

The client handles the Handler

/ * * *@author huangfu
 * @date* /
public class EchoClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();
        buffer.writeBytes("Hello Netty".getBytes(StandardCharsets.UTF_8)); ctx.channel().writeAndFlush(buffer); }}Copy the code

4. Client source code introduction

The code on the client side is basically the same as the code on the server side, so I won’t explain all of them here, just different ones:

EventLoopGroup worker = new NioEventLoopGroup();
Copy the code

The client has only one event loop group. Why? There is no new connection on the client.

Bootstrap bootstrap = new Bootstrap();
Copy the code

ServerBootstrap is basically the same as ServerBootstrap on the server side. It is a class that is used to save the configuration of the client side.

ChannelFuture channelFuture = bootstrap.connect().sync();
Copy the code

Connect to the server and wait for the link to complete!

The Handler overload method has also changed:

public void channelActive(ChannelHandlerContext ctx) throws Exception {....}
Copy the code

The implication here is that when the client is activated and connected to the server, the logic is called back!

For those of you who are careful, you might find that there are two methods: Handler and childHandler

.handler()
// Set the service pipeline
.childHandler()
Copy the code
  • Handler: Is bound to ServerSocketChannel, responsible for server logic processing!
  • ChildHandler: Is bound to a SockerChannel. A SocketChannel object is generated to call this handler’s binding when the client is bound to a SockerChannel.

conclusion

This lesson is relatively simple, mainly on the basic use of Netty has a relatively simple cognition, I hope you can practice more after class, to be able to use Netty simply!