Netty learning (1)-Netty entry and Netty application combat

1. What is Netty

Netty's official website defines Netty as follows:

Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers & clients.

In human language (Google Translate), it is:

Netty is an asynchronous event-driven network application framework for rapid development of maintainable high-performance protocol server and client.

Simply put, Netty has the following characteristics:

  • Design: suitable for different protocols (blocking and non-blocking); customizable thread model;
  • Performance: better throughput and low latency; save resources; reduce unnecessary memory copies; the provided Reactor thread model can achieve efficient concurrent processing;
  • Security: complete SSL/TLS and STARTTLS support;
  • Easy to use: NIO with JDK encapsulated, greatly simplifying NIO programming; and it comes with its own sticky package and unpacking. Mechanisms such as anomaly detection;
  • Application: Good application and verification in message middleware and distributed communication framework (Dubbo uses Netty as the basic communication framework by default);

Two, Netty entry demo

In this section, we will build a demo of a voice robot to understand the usage of Netty. The main functions implemented are: the client sends a query command, the server responds according to the command received through the Netty framework, and displays it on the client.

First import the dependencies needed by Netty. This time I use the 4.x version:

<dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.1.6.Final</version>
 </dependency>

The server
first is the establishment of the server. The role of the server is to receive client commands, process the commands, and respond. The whole process is as follows:

  • Create two NioEventLoopGroup instances, one is used to accept client connections; the other is used to read and write SocketChannel;
  • Create ServerBootstrap, which is used to start the auxiliary startup class of the NIO server;
  • Call the group method of creating ServerBootstrap and pass in two NioEventLoopGrou as parameters;
  • Create a NioServerSocketChannel, set the TCP parameters, and set the backlog to 1024 (when the server receives the client's TCP connection, it can only process one at a time, and if there are more, the request will be placed in the queue, and the backlog specifies the queue size);
  • Binding ChildChanelHandler, creating a pipeline, processing network I/O events, message encoding and decoding, etc.;
  • The thread group is blocked and closed;
/**
 * Created by wanggenshen
 * Date: on 2019/5/16 00:49.
 * Description: 机器人服务端, 用于接收指令, 并对指令作出新响应
 */
public class RobotServer {
    
    

    public static void bind(int port) throws InterruptedException {
    
    
        // 用于服务端接受客户端连接
        EventLoopGroup parentGroup = new NioEventLoopGroup();
        // 用于进行SocketChannel的网络读写
        EventLoopGroup workGroup = new NioEventLoopGroup();
        try {
    
    
            // 启动NIO服务端辅助启动类
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(parentGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    // 用于处理网络I/O事件,如记录日志、对消息进行编解码等
                    .childHandler(new ChildChanelHandler());

            // 绑定端口, 同步等待成功
            ChannelFuture future = bootstrap.bind(port).sync();
            // 等待服务端端口关闭
            future.channel().closeFuture().sync();
        } finally {
    
    
            // 优雅关闭线程池资源
            parentGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }


    }

/**
 * ChildChanelHandler可完成消息编解码、心跳、流量控制等功能
 */
    private static class ChildChanelHandler extends ChannelInitializer<SocketChannel> {
    
    

        @Override
        protected void initChannel(SocketChannel channel) throws Exception {
    
    
            channel.pipeline().addLast(new SimpleChannelInboundHandler() {
    
    
                @Override
                protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object command) throws Exception {
    
    
                    // 读取指令
                    ByteBuf byteBuf = (ByteBuf) command;
                    byte[] req = new byte[byteBuf.readableBytes()];
                    byteBuf.readBytes(req);
                    // 打印读取的内容
                    System.out.println("Robot Server receive a command: " + new String(req, "UTF-8"));

                    // 处理指令
                    String result = "hello,你好!我叫Robot。";
                    if ("hello".equals(command)) {
    
    
                        result = new Date(result).toString();
                    }
                    // 将消息先放到缓冲数组中, 再全部发送到SocketChannel中
                    ByteBuf resp = Unpooled.copiedBuffer(result.getBytes());
                    channelHandlerContext.writeAndFlush(resp);
                }
            });
        }
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        RobotServer.bind(8080);
    }
}

Client
The role of the client is to send instructions to the server and print the processing results sent by the server on the console. The whole process is as follows:

  • Create an EventLoopGroup for the client to handle I/O reads and writes;
  • Create a client startup auxiliary class Bootstrap, and bind the NioEventLoopGroup parameter;
  • Set the channel. The difference from the server is that the channel of the client is NioSocketChannel;
  • Set the TCP parameter ChannelOption.TCP_NODELAY;
  • Add the handler class, monitor the channel, and handle events;
  • Call connect to initiate an asynchronous connection and wait for the connection to succeed;
  • After the connection is closed, the client main function exits and the thread group is released.
/**
 * Created by wanggenshen
 * Date: on 2019/5/16 01:10.
 * Description: 机器人客户端, 发送指令, 并接收指令响应
 */
public class RobotClient {
    
    

    public void connect(int port, String host) throws InterruptedException {
    
    
        // 配置客户端NIO线程组, 用于客户端I/O读写
        EventLoopGroup group = new NioEventLoopGroup();

        try {
    
    
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
    
    
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
    
    
                            socketChannel.pipeline()
                                    .addLast(new SimpleChannelInboundHandler() {
    
    

                                        @Override
                                        protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
    
    
                                            ByteBuf byteBuf = (ByteBuf) msg;
                                            byte[] response = new byte[byteBuf.readableBytes()];
                                            byteBuf.readBytes(response);

                                            System.out.println("Client: " + new String(response, "UTF-8"));
                                        }

                                        @Override
                                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
    
    
                                            final ByteBuf firstMsg;
                                            byte[] req = "hello".getBytes();
                                            firstMsg = Unpooled.buffer(req.length);
                                            firstMsg.writeBytes(req);
                                            ctx.channel().writeAndFlush(firstMsg);
                                            super.channelActive(ctx);
                                        }

                                    });
                        }
                    });

            // 发起异步连接
            ChannelFuture future = bootstrap.connect(host, port);
            // 等待客户端关闭
            future.channel().closeFuture().sync();
        } finally {
    
    
            group.shutdownGracefully();
        }

    }

    public static void main(String[] args) throws InterruptedException {
    
    
        new RobotClient().connect(8080, "127.0.0.1");
    }
}

Operation and test
run the server, and then run the client;
after running the server, server receives a hellocommand:
Insert picture description here

Then the server responds to this command, the response content is hello,你好!我叫Robot., and the response content is sent to the buffer.

The client receives the content sent by the server and displays it in the console: In
Insert picture description here
this way, a simple server-client communication applet is implemented based on Netty.

Server and client running sequence diagram
Server running sequence diagram:
Insert picture description here

Client running sequence diagram:
Insert picture description here


Reference:
"Netty Authoritative Guide"
Netty official website: https://netty.io/

Guess you like

Origin blog.csdn.net/noaman_wgs/article/details/95518785