[java network programming] netty framework

1. Introduction

Netty is a high-performance, asynchronous event-driven NIO framework. It is based on the API provided by Java Nio and provides support for TCP, UDP and file transfer.

2. Reactor model

Reactor is an event-driven model for concurrently processing responses to client requests. After receiving the client request, the server adopts a multiplexing strategy to receive all client requests asynchronously through a non-blocking thread.

(1) Reactor single-threaded model

A thread is responsible for establishing connections, reading, writing and other operations. If there is a time-consuming operation in the processing of the business, it will cause a delay in the processing of all requests.

 (2) Reactor multithreading model

Only in the case of a single-threaded model, use the thread pool to manage multiple threads, and use multiple threads to process business.

(3) Reactor master-slave multithreading model

This model uses a main Reactor to only handle connections, while multiple sub-Reactors are used to handle IO reads and writes. Then hand it over to the thread pool to handle the business. Tomcat is implemented using this mode. efficient

3. The core components of Netty

(1)BootStrap/ServerBootStrap

BootStrap is used for client service startup. ServerBootStrap is used for server startup.

(2)NioEventLoop

Execute event operations based on thread queues. The specific event operations to be executed include connection registration, port binding, and I/O data reading and writing. Each NioEventLoop thread is responsible for event processing of multiple Channels.

(3)NioEventLoopGroup

Manage the life cycle of NioEventLoop

(4)Future/ChannelFuture

For the realization of asynchronous communication, based on the asynchronous communication method, an event can be registered after the I/O operation is triggered, and the monitoring event is automatically triggered after the I/O operation (data reading and writing is completed or failed) is completed and subsequent operations are completed.

(5)Channel

It is a network communication component in netty, which is used to perform specific I/O operations. The main functions include: establishment of network connection, management of connection status, configuration of network connection parameters, network data operation based on asynchronous NIO.

(6)Selector

Channel management for I/O multiplexing

(7)ChannelHandlerContext

Management of Channel context information. Each ChannelHandler corresponds to a ChannelHandlerContext.

(8)ChannelHandler

Interception and processing of I/O events.

Among them, ChannelInBoundHandler is used to handle the I/O operation of data reception.

Among them, ChannelOutBoundHandler is used to handle the I/O operation of data transmission.

(9)ChannelPipeline

Event interception, processing and forwarding based on the interceptor design pattern.

Each Channel corresponds to a ChannelPipeline. In the ChannelPipeline, a doubly linked list composed of ChannelHandlerContext is maintained. Each ChannelHandlerContext corresponds to a ChannelHandker to complete the interception and processing of specific Channel events.

Fourth, the operating principle of netty

Server workflow:

1. When the server starts, bind a local port and initialize NioServerSocketChannel.

2. Register your own NioServerSocketChannel to a selector of a BossNioEventLoopGroup.

The server side contains 1 Boss NioEventLoopGroup and 1 Worker NioEventLoopGroup

Boss NioEventLoopGroup is responsible for receiving client connections, and Worker NioEventLoopGroup is responsible for network read and write.

NioEventLoopGroup is equivalent to an event loop group, which contains multiple event loops NioEventLoop, each NioEventLoop contains a selector and an event loop thread.

The tasks performed by BossNioEventLoopGroup loop:

  1. Poll accept event;
  2. Process the accept event, and register the generated NioSocketChannel to a Selector of a WorkNioEventLoopGroup.
  3. Process tasks in the task queue, runAllTasks. The tasks in the task queue include tasks executed by the user calling eventloop.execute or schedule, or tasks submitted to the eventloop by other threads.

The tasks performed by WorkNioEventLoopGroup loop:

  1. Polling for read and write events
  2. Handle IO events, when NioSocketChannel readable and writable events occur, callback (trigger) ChannelHandler for processing.
  3. Process tasks in the task queue, ie runAllTasks

5. How does netty solve the problem of sticking and unpacking

Use a decoder to solve, there are 4 kinds of decoders

 ch.pipeline().addLast(new LengthFieldBasedFrameDecoder());
  1. Fixed-length unpacker FixedLengthFrameDecoder , the splitting of each application layer packet is a fixed-length size
  2. Line unpacking device LineBasedFrameDecoder , each application layer data packet is split with a newline character as a separator
  3. Delimiter unpacker DelimiterBasedFrameDecoder , each application layer data packet is split by custom delimiter
  4. An unpacker based on the length of the data packet, LengthFieldBasedFrameDecoder uses the length of the application layer data packet as the basis for splitting the application layer data packet at the receiving end. (commonly used)

6. Why is the performance of netty so high

(1) Network model (I/O multiplexing model)

Multiplexing IO, using one thread to process connection requests, multiple threads to process IO requests, it can handle more requests than BIO, data requests and data processing are asynchronous, the underlying layer uses linux select, poll, epoll

(2) Data zero copy

Netty's data receiving and sending all use external direct memory for socket reading and writing, and the off-heap memory can be directly used in the operating system memory, without the need for secondary copying of the byte buffer back and forth. At the same time, netty provides combined buffer objects, which can avoid the performance loss caused by the traditional way of merging buffers through memory copy.

Netty file transfer is operated by transferTo method, completely zero copy.

(3) Memory reuse mechanism

Use off-heap direct memory, reuse buffers, and do not require jvm to reclaim memory

(4) Lock-free design

Netty internally adopts a serial lock-free design for I/O operations to avoid performance degradation caused by multi-thread competition for CPU and resource locking.

(5) High-performance serialization framework

Serialization of data using google's protoBuf

(6) Use the FastThreadLocal class

Use the FastThreadLocal class instead of the ThreadLocal class

Seven, netty use

1. Introduce dependencies


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

2. Write server code (fixed writing method)

public class Server {  
  
    private int port;  
  
    public Server(int port) {  
        this.port = port;  
    }  
  
    public void run() {  
        EventLoopGroup bossGroup = new NioEventLoopGroup(); //用于处理服务器端接收客户端连接  
        EventLoopGroup workerGroup = new NioEventLoopGroup(); //进行网络通信(读写)  
        try {  
            ServerBootstrap bootstrap = new ServerBootstrap(); //辅助工具类,用于服务器通道的一系列配置  
            bootstrap.group(bossGroup, workerGroup) //绑定两个线程组  
                    .channel(NioServerSocketChannel.class) //指定NIO的模式  
                    .childHandler(new ChannelInitializer<SocketChannel>() { //配置具体的数据处理方式  
                        @Override  
                        protected void initChannel(SocketChannel socketChannel) throws Exception {  
                            socketChannel.pipeline().addLast(new ServerHandler());  
                        }  
                    })  
                    /** 
                     * 对于ChannelOption.SO_BACKLOG的解释: 
                     * 服务器端TCP内核维护有两个队列,我们称之为A、B队列。客户端向服务器端connect时,会发送带有SYN标志的包(第一次握手),服务器端 
                     * 接收到客户端发送的SYN时,向客户端发送SYN ACK确认(第二次握手),此时TCP内核模块把客户端连接加入到A队列中,然后服务器接收到 
                     * 客户端发送的ACK时(第三次握手),TCP内核模块把客户端连接从A队列移动到B队列,连接完成,应用程序的accept会返回。也就是说accept 
                     * 从B队列中取出完成了三次握手的连接。 
                     * A队列和B队列的长度之和就是backlog。当A、B队列的长度之和大于ChannelOption.SO_BACKLOG时,新的连接将会被TCP内核拒绝。 
                     * 所以,如果backlog过小,可能会出现accept速度跟不上,A、B队列满了,导致新的客户端无法连接。要注意的是,backlog对程序支持的 
                     * 连接数并无影响,backlog影响的只是还没有被accept取出的连接 
                     */  
                    .option(ChannelOption.SO_BACKLOG, 128) //设置TCP缓冲区  
                    .option(ChannelOption.SO_SNDBUF, 32 * 1024) //设置发送数据缓冲大小  
                    .option(ChannelOption.SO_RCVBUF, 32 * 1024) //设置接受数据缓冲大小  
                    .childOption(ChannelOption.SO_KEEPALIVE, true); //保持连接  
            ChannelFuture future = bootstrap.bind(port).sync();  
            future.channel().closeFuture().sync();  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            workerGroup.shutdownGracefully();  
            bossGroup.shutdownGracefully();  
        }  
    }  
  
    public static void main(String[] args) {  
        new Server(8379).run();  
    }  
}  

 3. Write Handler processing class


public class ServerHandler  extends ChannelHandlerAdapter {  
  
    @Override  
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
      
            //do something msg  
            ByteBuf buf = (ByteBuf)msg;  
            byte[] data = new byte[buf.readableBytes()];  
            buf.readBytes(data);  
            String request = new String(data, "utf-8");  
            System.out.println("Server: " + request);  
            //写给客户端  
            String response = "我是反馈的信息";  
            ctx.writeAndFlush(Unpooled.copiedBuffer("888".getBytes()));  
            //.addListener(ChannelFutureListener.CLOSE);  
              
  
    }  
  
    @Override  
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
        cause.printStackTrace();  
        ctx.close();  
    }  
  
}  

Guess you like

Origin blog.csdn.net/sumengnan/article/details/125089866