Introduction to netty

Posted by nobodyk on Wed, 09 Feb 2022 05:25:23 +0100

I What is netty? Why use netty
Netty is an open source java framework provided by jboss. Netty provides asynchronous and event driven network application framework and tools to quickly develop high-performance and high availability network server and client programs. In other words, netty is a nio based programming framework. Using netty can quickly develop a network application.

Because the nio api of java is very complex to use, and Epoll Bug may appear, it is very difficult and time-consuming for us to use the native nio for network programming. However, the good design of netty can enable developers to develop network applications quickly and efficiently.

II The functional characteristics and architecture of netty
As shown in the figure below: the core of netty is bytebuf buffer object supporting zero copy, general communication api and extensible event model; It supports a variety of transport services and a series of common protocols such as HTTP, Protobuf, binary, text, WebSocket, as well as user-defined protocols.

netty's model is based on reactor multithreading model, in which mainReactor is used to receive client requests and forward them to subreactor. Subreactor is responsible for the read-write requests of the channel. The tasks of non IO requests (specific logical processing) will be directly written to the queue and wait for worker threads to process.

III Some core concepts in netty

1.bootstrap, serverBootstrap: bootstrap means boot. Its main function is to configure the entire netty program and integrate various components. serverBootstrap is a server-side boot class. Bootstrap is used to connect to the remote host. It has an EventLoopGroup; serverBootstrap is used to listen to the local port. There are two eventloopgroups.

2.eventLoop: eventLoop maintains a thread and task queue and supports asynchronous submission and execution of tasks.

3.eventLoopGroup: eventLoopGroup mainly manages the life cycle of eventLoop. It can be regarded as a thread pool. It internally maintains a group of eventloops. Each eventLoop corresponds to multiple channels, while a Channel can only correspond to one eventLoop.

4.channelPipeLine: a list containing channelHandler, which is used to set the execution order of channelHandler.

5.Channel: channel represents the open link of an entity (such as a hardware device, a file, a network socket or a program component that can perform one or more different IO operations), such as read and write operations.

6.Futrue, ChannelFuture: future provides another way to notify the application when the operation is completed. This object can be regarded as a placeholder for the result of asynchronous operation; It will be completed at some point in the future and provide access to its results. Every outbound operation of netty will return a ChannelFuture. A listener can be registered in the future. When the corresponding event occurs, it will start the listener.

7.ChannelInitializer: it is a special ChannelInboundHandler, which initializes the channel when it is registered to eventLoop

8.ChannelHandler: code used to process business logic. ChannelHandler is a parent interface, which is inherited by channelboundhandler and ChannelOutboundHandler. They are used to process inbound and outbound respectively.

9.ChannelHandlerContext: allows its associated ChannelHandler to interact with its associated ChannelPipeline and other channelhandlers. It can notify the next ChannelHandler in the same ChannelPipeline, or dynamically modify the ChannelPipeline to which it belongs.

IV The commonly used built-in decoder and encoder in netty (only one corresponding to the codec name is listed)

1.DelimiterBasedFrameDecoder: separator decoder, which takes the set symbol as the end of the message to solve the problem of sticking packets

2.FixedLengthFrameDecoder: fixed length decoder, which is used for fixed length messages

3.LineBasedFrameDecoder: it is divided according to each line, that is, a special separator decoder. Its separator is \ n or \ r\n.

The length of the message in the package is set by pasting the length of the field basedlender4. The decoder has a total of 5 parameters

5.LengthFieldBasedFrameDecoder(int maxFrameLength, the maximum size of a single package)

int lengthFieldOffset: defines the offset of the length field from the beginning of the packet

int lengthFieldLength, which defines the number of bytes occupied by the length field

int lengthAdjustment, lengthAdjustment = number of bytes of packets left after the data length field - data length value (that is, other information of all non data after the length field)

int initialBytesToStrip) the number of bytes to ignore, starting from the header

6.HttpRequestDecoder: decodes bytes into HttpRequest, HttpContent and LastHttpContent messages

7.HttpResponseDecoder: decode bytes into HttpResponse, HttpContent and LastHttpContent messages

8.ReplayingDecoder: a special ByteToMessageDecoder, which can realize non blocking decoding in blocking i/o mode. The biggest difference between ReplayingDecoder and ByteToMessageDecoder is that ReplayingDecoder allows you to implement decode() and decodeLast() as if all bytes have been received, without judging the available bytes

9.Base64Decoder: Base64 encoder

10.StringDecoder: convert the received ByteBuf into String

11.ByteArrayDecoder: convert the received ByteBuf into a byte array

12. Datagram packet decoder: use the specified decoder to decode the received datagram packet

13.MsgpackDecoder: decoder used for Msgpack serialization

14.ProtobufDecoder: decoder used for Protobuf protocol transmission

15.HttpObjectAggregator: aggregate multiple parts of http message to form a FullHttpRequest or FullHttpResponse message.


LengthFieldPrepender: the encoder that adds the length of the message to the front end of the message. It is generally used in combination with LengthFieldBasedFrameDecoder

HttpServerCodec: equivalent to HttpRequestDecoder and HttpResponseEncoder

HttpClientCodec: equivalent to HttpRequestEncoder and HttpResponseDecoder

ChunkedWriteHandler: when transferring a large file, mapping all the contents of the file into memory at one time is likely to lead to memory overflow. ChunkedWriteHandler can solve the possible memory overflow problem in the process of large file or code stream transmission

V Simple use of netty

public class MyClient {

    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();
        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(nioEventLoopGroup).channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<Channel>() {

                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0,4,0,4))
                        .addLast(new LengthFieldPrepender(4))
                        .addLast(new StringDecoder(CharsetUtil.UTF_8))
                        .addLast(new StringEncoder(CharsetUtil.UTF_8))
                        .addLast(new SimpleChannelInboundHandler<String>() {

                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
                                System.out.println(ctx.channel().remoteAddress()+": "+msg);
                                ctx.writeAndFlush("Information from client");
                            }
                            
                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                for(int i=0;i<10;i++){
                                    ctx.writeAndFlush("Client page"+i+"Message");
                                }
                            }
                            
                            @Override
                            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                cause.printStackTrace();
                                ctx.close();
                            }
                        });
                    }
                    
                });
            
            ChannelFuture future = bootstrap.connect("localhost", 9999).sync();
            future.channel().closeFuture().sync();
            
        }finally{
            nioEventLoopGroup.shutdownGracefully().sync();
        }
    }

}
public class MyServer {

    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<Channel>() {

                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ch.pipeline()
                        .addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4,0,4))
                        .addLast(new LengthFieldPrepender(4))
                        .addLast(new StringDecoder(CharsetUtil.UTF_8))
                        .addLast(new StringEncoder(CharsetUtil.UTF_8))
                        .addLast(new SimpleChannelInboundHandler<String>() {
                            
                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
                                System.out.println(ctx.channel().remoteAddress()+":"+msg);
                                ctx.writeAndFlush("from server: "+UUID.randomUUID());
                            }
                            
                            @Override
                            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                cause.printStackTrace();
                                ctx.close();
                            }
                        });
                    }
                });
            ChannelFuture future = serverBootstrap.bind(9999).sync();
            future.channel().closeFuture().sync();
        }finally{
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
        }
    }

}

Topics: Java Back-end