Getting Started with Netty_Basic Overview (2)

1. What is Netty? NIO synchronous non-blocking model

Netty official website: https://netty.io
Insert picture description here

  1. Netty is a Java open source framework provided by JBOSS and is now an independent project on Github;
  2. Netty is 异步, 基于事件驱动the network application framework for rapid development of high-performance, high-reliability network IO program;
  3. Netty is mainly aimed at high-concurrency applications facing Clients under the TCP protocol;
  4. Netty is essentially a NIO framework, suitable for a variety of application scenarios related to server communication; to thoroughly understand Netty, you must know what NIO is;

As an asynchronous high-performance communication framework, Netty is often used by the RPC framework as a basic communication component. (Remote Procedure Call (RPC, Remote Procedure Call): RPC is an inter-process communication method. The current mainstream RPC frameworks in the industry include Alibaba’s Dubbo, Google’s open source gRPC, Apache (formerly Facebook)’s Thrift, and Sina Weibo’s Montan etc.)

The previous article introduced NIO, so why did Netty appear? That is, the shortcomings of
NIO, the problems with native NIO

  1. NIO's class library and API are complicated and troublesome to use: you need to be proficient in Selector, ServerSocketChannel, SocketChannel, ByteBuffer, etc.
  2. Need to have other additional skills: to be familiar with Java multi-threaded programming, because NIO programming involves the Reactor
    mode, you must be very familiar with multi-threading and network programming in order to write high-quality NIO programs.
  3. The development workload and difficulty are very large: for example, the client is facing disconnection and reconnection, network flash interruption, half-packet read and write, failed cache, network congestion and abnormal flow processing.
  4. JDK NIO bug: For example, the infamous Epoll Bug, it will cause Selector empty polling, and eventually lead to 100% CPU. This problem still exists until the JDK 1.7 version and has not been fundamentally solved.

Netty official website description:

  1. Netty is a Java open source framework provided by JBOSS. Netty provides an asynchronous, event-driven network application framework for rapid development of high-performance, high-reliability network I0 programs
  2. Netty can help you develop a network application quickly and simply, which is equivalent to simplifying and streamlining the development process of NIO
  3. Netty is currently the most popular theater industry, communications industry, etc., which has been widely used. The well-known Elasticsearch and Dubbo frameworks all use Netty.

Advantages of
Netty Netty encapsulates the NIO API that comes with the JDK to solve the above problems.
1) Elegant design: unified API blocking and non-blocking sockets for various transmission types; based on a flexible and extensible event model, which can clearly separate concerns; highly customizable threading model-single thread, one or more Thread pool
2) Easy to use: well-documented Javadoc, user guide and examples; no other dependencies, JDK 5 (Netty3.x) or 6 (Netty4.x) is sufficient.
3) High performance and higher throughput: lower latency; reduce resource consumption; minimize unnecessary memory copy.
4) Security: Complete SSL/TLS and StartTLS support.
5) The community is active and constantly updated: the community is active, the version iteration cycle is short, the bugs found can be fixed in time, and more new features will be added

2. Basic introduction to threading model

The threading models that currently exist are:

  1. Traditional blocking IO service model
  2. Reactor model
    According to the number of Reactor and the number of processing resource pool threads, there are 3 typical implementations:
  3. Single Reactor single thread
  4. Single Reactor multi-threaded
  5. Master-slave Reactor multithreading

The Netty threading model is mainly based on the master-slave Reactor multi-threading model and has made certain improvements. The master-slave Reactor multi-threading model has multiple Reactors.

.Reactor model

Solutions to the two shortcomings of the traditional IO model:

1) Based on the I/O reuse model: multiple connections share a blocking object. The application only needs to wait on a blocking object, without blocking waiting for all connections. When a connection has new data to be processed, the operating system informs the application that the thread returns from the blocking state and starts business processing.
2) Reuse thread resources based on the thread pool: It is no longer necessary to create threads for each connection. After the connection is completed, the business processing tasks are allocated to the thread pool for processing. One thread can handle the business of multiple connections.

Reactor corresponding names: reactor mode, distributor mode, ruler mode

…The core composition of the Reactor model

Reactor: Runs in a separate thread, responsible for monitoring and distributing events, and dispatching them to appropriate handlers to respond to IO events. It is like a company's telephone operator, who answers calls from customers and transfers the route to the appropriate Contact
Handlers: The actual events to be completed by the handlers to execute I/O events, similar to actual officials in the company that customers want to talk to. Reactor tubes respond to I/O events by scheduling appropriate handlers, and the handlers execute non- Blocking operation.

.Single Reactor single thread

Insert picture description here

  1. Advantages: The model is simple, there is no problem of multi-threading, process communication, competition, all are completed in 1 thread
  2. Disadvantages: performance issues, only one thread, unable to fully utilize the performance of multi-core CPU. When the Handler is processing the business on a certain connection, the entire process cannot handle other connection events, which can easily lead to performance bottlenecks
  3. Disadvantages: reliability problems, unexpected termination of threads, or infinite loops, will cause the communication module of the entire system to be unavailable, unable to receive and process external messages, and cause node failure
  4. Usage scenario: The number of clients is limited, and business processing is very fast. For example, the time complexity of Redis in business processing is 0 (1)

.Reactor multithreading

Insert picture description here

.Netty model

Netty has made certain improvements mainly based on the master-slave Reactors multithreading model.

Three, Netty quick start example

Service-Terminal

package com.lsh.netty.simple;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @author :LiuShihao
 * @date :Created in 2020/9/21 4:46 下午
 * @desc :
 */
public class NettyServer {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        //创建BossGroup 和 WorkerGroup
        //创建两个线程组
        //BossGroup只处理连接请求,真正的和客户端业务处理,会交给workerGroup处理  两个都是无限循环
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        //创建服务器端的启动对象,配置参数
        try {
    
    
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)//使用NioSocketChannel作为服务器的通道实现
                .option(ChannelOption.SO_BACKLOG, 128)//设置线程队列得到连接个数
                .childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动连接的状态
                .childHandler(new ChannelInitializer<SocketChannel>() {
    
    
                    protected void initChannel(SocketChannel ch) throws Exception {
    
    //创建一个通道测试对象 匿名对象
                        ch.pipeline().addLast(new NettyServerHandler());//给pipeline设置处理器
                    }
                });//给workerGroup 的EventLoop 对应的g管道设置处理器

        System.out.println("服务器 is Ok~");
        ChannelFuture cf = serverBootstrap.bind(6666).sync();//绑定一个端口并且同步处理
        //对 关闭通道  进行监听
        cf.channel().closeFuture().sync();
        }finally {
    
    
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}

Server-side processor

package com.lsh.netty.simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

/**
 * @author :LiuShihao
 * @date :Created in 2020/9/21 5:08 下午
 * @desc :
 *
 *          自定义一个Handler需要继承Netty规定的ChannelInboundHandlerAdapter
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    
    
    /**
     * 可以读取客户端发送的消息
     * @param ctx  上下文对象:  管道pipeline,通道channel,地址
     * @param msg   客户端发送的数据:默认是Object
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    
    

        System.out.println("server ctx:"+ctx);
        //将msg 转成一个 ByteBuf  (Netty提供的,不是NIO的ByteBuffer)
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("客户端发送的消息时:"+byteBuf.toString(CharsetUtil.UTF_8));
        System.out.println("客户端地址:"+ctx.channel().remoteAddress());
    }

    /**
     * 数据读取完毕
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    
    
        //write和flish   将数据写入缓冲 并刷新
        //一般来讲 我们对发送的数据进行编码
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello!客户端~",CharsetUtil.UTF_8));

    }

    /**
     * 发生异常   一般是需要关闭通道
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    
    
        ctx.close();
    }
}

Client

package com.lsh.netty.simple;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * @author :LiuShihao
 * @date :Created in 2020/9/22 9:35 上午
 * @desc : 客户端需要一个事件循环组
 */
public class NettyClient {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    
        //客户端需要一个事件循环组
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
    
    
        //创建客户端启动对象  注意  创建的不是ServerBootstrap   而是BootStrap  netty包下的
        Bootstrap bootstrap = new Bootstrap();
         //设置相关参数
        bootstrap.group(group)//设置线程组
                .channel(NioSocketChannel.class)//设置客户端通道实现类
                .handler(new ChannelInitializer<SocketChannel>() {
    
    
                    protected void initChannel(SocketChannel ch) throws Exception {
    
    
                        ch.pipeline().addLast(new NettyClinetHandler());
                    }
                });
        System.out.println("客户端 is OK~");
        ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6666).sync();
        channelFuture.channel().closeFuture().sync();
        }finally {
    
    
            group.shutdownGracefully();
        }
    }
}

Client processor

package com.lsh.netty.simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

/**
 * @author :LiuShihao
 * @date :Created in 2020/9/22 9:50 上午
 * @desc :
 */
public class NettyClinetHandler extends ChannelInboundHandlerAdapter {
    
    
    /**
     * 当通道就绪就会触发该方法
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
    
    
        System.out.println("Client:"+ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello Server~", CharsetUtil.UTF_8));
    }

    /**
     * 当通道有读取事件 发生时 就会触发
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    
    
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("服务器回复的消息:"+byteBuf.toString(CharsetUtil.UTF_8));
        System.out.println("服务器的地址:"+ctx.channel().remoteAddress());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    
    
        cause.printStackTrace();
        ctx.close();
    }
}

running result

Insert picture description here

Insert picture description here

Guess you like

Origin blog.csdn.net/DreamsArchitects/article/details/108344196