4, Core composition of Netty

This document is compiled from Han Shunping Netty tutorial of shangsilicon valley

https://www.bilibili.com/video/BV1DJ411m7NR

1,Bootstrap,ServerBootstrap

Bootstrap means boot. A Netty application usually starts with a bootstrap. Its main function is to configure the whole Netty program and connect various components in series. Bootstrap class in Netty is the boot class of client program, and ServerBootstrap is the boot class of server

Common methods:

Method nameMethod introduction
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup)This method is used on the server side to set two eventloops
public B group(EventLoopGroup group)This method is used for the client to set an EventLoop
public B channel(Class<? extends C> channelClass)This method is used to set up a server-side channel implementation
public <T> B option(ChannelOption<T> option, T value)Used to add a channel to the server configuration
public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value)Used to add configuration to the received channel
public ServerBootstrap childHandler(ChannelHandler childHandler)This method is used to set the business processing class (custom handler)
public ChannelFuture bind(int inetPort)This method is used on the server side to set the occupied port number
public ChannelFuture connect(String inetHost, int inetPort)This method is used for the client to connect to the server

2,Future,ChannelFuture

All IO operations in Netty are asynchronous, and it is impossible to know immediately whether the message is processed correctly. However, you can wait for it to complete or register a listener directly. The specific implementation is that they can register a listener through Future and ChannelFuture. When the operation succeeds or fails, the listener will automatically trigger the registered listening event

Common methods

Method nameMethod introduction
Channel channel()Returns the channel for which the IO operation is currently in progress
ChannelFuture sync()Waiting for the asynchronous operation to complete is equivalent to blocking the current.

3,Channel

  • The component of Netty network communication, which can be used to perform network I/O operations.
  • Through Channel, you can obtain the status of the Channel currently connected to the network
  • The configuration parameters of the network connection (such as the size of the receive buffer) can be obtained through the Channel
  • Channel provides asynchronous network I/O operations (such as establishing connection, reading and writing, binding port). Asynchronous call means that any I/O call will be returned immediately, and it does not guarantee that the requested I/O operation has been completed at the end of the call
  • The call immediately returns an instance of ChannelFuture. By registering the listener on ChannelFuture, you can call back to notify the caller when the I/O operation succeeds, fails or cancels
  • Support associated I/O operations and corresponding handlers
  • Connections with different protocols and blocking types have different Channel types corresponding to them

Common Channel types

nameintroduce
NioSocketChannelAsynchronous client TCP Socket connection.
NioServerSocketChannelAsynchronous server-side TCP Socket connection
NioDatagramChannelAsynchronous UDP connection.
NioSctpChannelAsynchronous client Sctp connection.
NioSctpServerChannelAsynchronous Sctp server-side connection. These channels cover UDP and TCP network IO and file IO.

4,Selector

  • Netty implements I/O multiplexing based on Selector object. One thread of Selector can listen to Channel events of multiple connections.
  • After registering a Channel with a Selector, the internal mechanism of the Selector can automatically and continuously query (Select) whether these registered channels have ready I/O events (such as readable, writable, network connection completion, etc.), so that the program can simply use one thread to efficiently manage multiple channels
  • At the same time, the selectedKey set in the Selector is replaced by a set set implemented by itself in Netty, which is more efficient.

5. ChannelHandler and its implementation class

  • ChannelHandler is an interface that handles I/O events or intercepts I/O operations and forwards them to the next handler in its channelpipeline.
  • ChannelHandler itself does not provide many methods, because this interface has many methods that need to be implemented. During use, it can inherit its subclasses
  • We often need to customize a Handler class to inherit the ChannelInboundHandlerAdapter, and then implement the business logic by rewriting the corresponding methods. Next, let's see which methods we generally need to override
public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {

    //Channel registration event
    @Skip
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelRegistered();
    }

    //Channel deregistration event
    @Skip
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelUnregistered();
    }

    //Channel ready event
    @Skip
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelActive();
    }

    /**
     * Calls {@link ChannelHandlerContext#fireChannelInactive()} to forward
     * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     *
     * Sub-classes may override this method to change behavior.
     */
    @Skip
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelInactive();
    }

    //Channel read data event
    @Skip
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.fireChannelRead(msg);
    }

    //Event triggered after reading channel data
    @Skip
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelReadComplete();
    }

    /**
     * Calls {@link ChannelHandlerContext#fireUserEventTriggered(Object)} to forward
     * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     *
     * Sub-classes may override this method to change behavior.
     */
    @Skip
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        ctx.fireUserEventTriggered(evt);
    }

    /**
     * Calls {@link ChannelHandlerContext#fireChannelWritabilityChanged()} to forward
     * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     *
     * Sub-classes may override this method to change behavior.
     */
    @Skip
    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelWritabilityChanged();
    }

    //An abnormal event occurred in the channel
    @Skip
    @Override
    @SuppressWarnings("deprecation")
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        ctx.fireExceptionCaught(cause);
    }
}

  • ChannelInboundHandler is used to handle inbound I/O events.
  • ChannelOutboundHandler is used to handle outbound I/O operations.

Adapter

  • The ChannelInboundHandlerAdapter is used to handle inbound I/O events.
  • The ChannelOutboundHandlerAdapter is used to handle outbound I/O operations.
  • ChannelDuplexHandler is used to handle inbound and outbound events.

6. Pipeline and ChannelPipeline

  • ChannelPipeline is a collection of handlers, which is responsible for handling and intercepting inbound or outbound events and operations. It is equivalent to a chain running through Netty. (it can also be understood in this way: ChannelPipeline is a List that saves ChannelHandler and is used to handle or intercept inbound events and outbound operations of Channel)
  • ChannelPipeline implements an advanced form of interception filter mode, which enables users to fully control the processing of events and how the channelhandlers in the Channel interact with each other
  • In Netty, each Channel has and only one ChannelPipeline corresponds to it
  • A Channel contains a ChannelPipeline, which maintains a two-way linked list composed of ChannelHandlerContext, and each ChannelHandlerContext is associated with a ChannelHandler
  • Inbound events and outbound events are in a two-way linked list. Inbound events will be passed from the head of the linked list to the last inbound handler, and outbound events will be passed from the tail of the linked list to the first outbound handler. The two types of handlers do not interfere with each other

Common methods:

Method nameintroduce
ChannelPipeline addFirst(ChannelHandler... handlers)Add a business handler to the first position in the chain
ChannelPipeline addLast(ChannelHandler... handlers)Add a business handler to the last position in the chain

7,ChannelHandlerContext

  • Save all context information related to the Channel and associate a ChannelHandler object at the same time
  • That is, the ChannelHandlerContext contains a specific event handler. At the same time, the ChannelHandlerContext is also bound with the corresponding pipeline and Channel information to facilitate the call of ChannelHandler

Common methods:

Method nameintroduce
ChannelFuture close()Close channel
ChannelOutboundInvoker flush()Refresh
ChannelFuture writeAndFlush(Object msg)Write data to the next ChannelHandler of the current ChannelHandler in the ChannelPipeline and start processing (outbound)

8,ChannelOption

After creating a Channel instance, Netty generally needs to set the ChannelOption parameter.

The ChannelOption parameters are as follows:

  • ChannelOption. SO_ The TCP / log backup function is used to initialize the IP connection size of the server. The server processes client connection requests in sequence, so only one client connection can be processed at a time. When multiple clients come, the server puts the client connection requests that cannot be processed in the queue for processing. The backlog parameter specifies the size of the queue.
  • ChannelOption.SO_KEEPALIVE: keep the connection active all the time

9. EventLoopGroup and its implementation class NioEventLoopGroup

  • EventLoopGroup is an abstraction of a group of eventloops. In order to make better use of multi-core CPU resources, Netty generally has multiple eventloops working at the same time, and each EventLoop maintains a Selector instance.

  • EventLoopGroup provides the next interface. You can get one of the eventloops from the group according to certain rules to process tasks. In Netty server-side programming, we generally need to provide two eventloopgroups, such as BossEventLoopGroup and WorkerEventLoopGroup.

  • Usually, a service port, that is, a ServerSocketChannel, corresponds to a Selector and an EventLoop thread. BossEventLoop is responsible for receiving the connection from the client and handing the SocketChannel to the WorkerEventLoopGroup for IO processing, as shown in the following figure:

  • BossEventLoopGroup is usually a single threaded EventLoop. EventLoop maintains a Selector instance registered with ServerSocketChannel. BossEventLoop constantly polls the Selector to separate connection events

  • Usually OP_ACCEPT event, and then give the received SocketChannel to the WorkerEventLoopGroup

  • WorkerEventLoopGroup will select one of the eventloops by next to register the SocketChannel with its maintained Selector and handle its subsequent IO events

Common methods:

Method nameintroduce
public NioEventLoopGroup()Construction method
public Future<?> shutdownGracefully()Disconnect and close the thread

10,Unpooled

Netty provides a tool class specially used to operate buffers (that is, netty's data container)

common method

Method nameintroduce
public static ByteBuf copiedBuffer(CharSequence string, Charset charset)Returns a ByteBuffer object through the given data and character encoding (similar to the ByteBuffer in NIO, but different)

Code example

//Create a ByteBuf
//1. Create an object that contains an array and is a byte[10]
//2. In the buffer of netty, it is unnecessary to use flip to reverse the data before reading it
// The bottom layer maintains readerIndex and writeIndex
//The range written to the buffer is [writeIndex, capacity)
//The readable range in the buffer is [readerIndex, writeindex]. Using buf.readByte() will move the readerIndex pointer backward, and using buf.getByte(i) to get through the index will not move the pointer
ByteBuf byteBuf = Unpooled.buffer(10);
for (int i = 0; i < 10; i++) {
    byteBuf.writeByte(i);
}
//Gets the size of the buf
int capacity = byteBuf.capacity();
//output
for (int i = 0; i < byteBuf.capacity(); i++) {
    System.out.println(byteBuf.getByte(i));
    System.out.println(byteBuf.readByte());
}
byte[] content = byteBuf.array();
//Convert content to string
String c = new String(content, StandardCharsets.UTF_8);
//Array offset
int offset = byteBuf.arrayOffset();
//Get read offset
int readerIndex = byteBuf.readerIndex();
//Get write offset
int writerIndex = byteBuf.writerIndex();
//Get capacity
int capacity = byteBuf.capacity();
//Gets the number of bytes that can be read
int readableBytes = byteBuf.readableBytes();
//Get bytes of a location by index
byte aByte = byteBuf.getByte(0);
//Gets the character sequence of a range in Buf
CharSequence charSequence = byteBuf.getCharSequence(0, 4, StandardCharsets.UTF_8);

11. Netty group chat system

Example requirements:

  • Write a Netty group chat system to realize simple data communication between server and client (non blocking)
  • Realize multi crowd chat
  • Server side: it can monitor users online and offline, and realize message forwarding function
  • Client: through the channel, it can send messages to all other users without blocking, and accept messages sent by other users (forwarded by the server)
  • Objective: to further understand the programming mechanism of Netty non blocking network

Server side code:

/*************Startup class**************/
public class GroupChatServer {
    private int port; //Listening port
    public GroupChatServer(int port){
        this.port = port;
    }
    //Write the run method to process the request of the client
    public void run() throws InterruptedException {
        //Create two thread groups
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast("decoder", new StringDecoder()); //Add decoder to pipeline
                            pipeline.addLast("encoder", new StringEncoder()); //Add encoder
                            pipeline.addLast(new GroupChatServerHandler());
                        }
                    });
            System.out.println("netty Server startup");
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();

            //Listen for closing events
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        GroupChatServer groupChatServer = new GroupChatServer(7000);
        groupChatServer.run();
    }
}

/***********************Handler**********************/
public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> {

    //Define a channel group to manage all channels
    //GlobalEventExecutor.INSTANCE is a global event executor and a single instance
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    //This method indicates that the connection is established. Once the connection is established, it will be executed first
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        //This method will traverse all channels in the channelGroup and send messages instead of traversing ourselves
        channelGroup.writeAndFlush("[client]" + channel.remoteAddress() + sdf.format(new Date()) + "join the chat\n");
        //Add the current Channel to the ChannelGroup
        channelGroup.add(channel);
    }

    //Indicates that the channel is active and prompts xxx to go online
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().remoteAddress() + " " + sdf.format(new Date()) + "It's online~");
    }

    //Indicates that the channel is inactive, prompting xxx to go offline
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().remoteAddress() + " " + sdf.format(new Date()) + "Offline~");
    }

    //Indicates that the channel is disconnected and pushes xx customer's departure information to the current online customer
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channelGroup.writeAndFlush("[client]" + channel.remoteAddress() +" "+ sdf.format(new Date()) + "I am leaving\n");
        System.out.println("current channelGroup size:" + channelGroup.size());
    }

    //Read the data and forward the message
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        //Get current channel
        Channel channel = ctx.channel();
        //At this time, traverse the channelGroup and send back different messages according to different situations
        channelGroup.forEach(item -> {
            if (item != channel) {
                item.writeAndFlush("[customer]" + channel.remoteAddress() + "Message sent:" + msg + "\n");
            } else { //Send your message to yourself
                item.writeAndFlush("[own]Message sent:" + msg + "\n");
            }
        });
    }

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

Client code:

/*********************Startup class******************/
public class GroupChatClient {

    //attribute
    private final String host;
    private final int port;

    public GroupChatClient(String host, int port) {
        this.port = port;
        this.host = host;
    }

    public void run() throws InterruptedException {
        NioEventLoopGroup eventExecutors = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(eventExecutors)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //Join Handler
                            pipeline.addLast("decoder", new StringDecoder());
                            pipeline.addLast("encoder", new StringEncoder());
                            pipeline.addLast(new GroupChatClientHandler());
                        }
                    });
            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
            //Get channel
            Channel channel = channelFuture.channel();
            System.out.println("--------" + channel.localAddress() + "---------");
            //The client needs to enter information to create a scanner
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNextLine()){
                String msg = scanner.nextLine();
                //Send to the server through channel
                channel.writeAndFlush(msg + "\r\n");
            }
        } finally {
            eventExecutors.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new GroupChatClient("127.0.0.1", 7000).run();
    }
}

/*****************Handler*****************/
public class GroupChatClientHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(msg.trim());
    }
}

12. Netty heartbeat detection mechanism case

Example requirements:

  • Write a case of Netty heartbeat detection mechanism. When the server does not read for more than 3 seconds, it will prompt that the read is idle
  • When the server has no write operation for more than 5 seconds, it will prompt that the write is idle
  • When the server has no read or write operation for more than 7 seconds, it will prompt that the read and write is idle

Startup class:

public static void main(String[] args) throws InterruptedException {
    NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
    NioEventLoopGroup workerGroup = new NioEventLoopGroup();

    try {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .handler(new LoggingHandler(LogLevel.INFO))  //Add log processing Handler for requests in BossGroup
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    //Add an IdleStateHandler provided by netty
                    /**
                     * 1,IdleStateHandler It is a processor provided by netty to detect idle state
                     * 2,long readerIdleTime: Indicates how long it has not been read, and a heartbeat detection packet will be sent to detect whether it is still connected
                     * 3,long writerIdleTime: Indicates how long it has not been written, and a heartbeat detection packet will be sent to detect whether it is still connected
                     * 4,long allIdleTime: Indicates how long there has been no reading or writing, and a heartbeat detection packet will be sent to detect whether it is still connected
                     * 5,When the IdleStateEvent is triggered, it will be passed to the next Handler of the pipeline,
                     * Handle this event in the method area by calling (triggering) the userEventTriggered of the next Handler.
                      */
                    pipeline.addLast(new IdleStateHandler(3, 5, 7, TimeUnit.SECONDS));

                    //Add a Handler (custom) for further processing of idle detection
                    pipeline.addLast(new MyServerHandler());
                }
            });
        //Start the server and set it to synchronization mode.
        ChannelFuture channelFuture = serverBootstrap.bind(7000).sync();
        channelFuture.channel().closeFuture().sync();
    } finally {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

Handler:

public class MyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * @param ctx context
     * @param evt event
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            //Transition evt down to IdleStateEvent
            IdleStateEvent event = (IdleStateEvent)evt;
            String eventTye = null;
            switch (event.state()) {
                case READER_IDLE:
                    eventTye = "Read idle";
                    break;
                case WRITER_IDLE:
                    eventTye = "Write idle";
                    break;
                case ALL_IDLE:
                    eventTye = "Read write idle";
                    break;
            }
            System.out.println(ctx.channel().remoteAddress() +"---Timeout--" + eventTye);
            System.out.println("The server will handle it accordingly..");
        }
    }
}

13. Netty establishes a Websocket connection

Example requirements:

  • Http protocol is stateless. The request between browser and server responds once, and the connection will be re created next time
  • Requirements: realize full duplex interaction of long connection based on WebSocket
  • Change the constraint of multiple requests of Http protocol to realize a long connection, and the server can send messages to the browser
  • The client browser and the server will perceive each other. For example, when the server is closed, the browser will perceive. Similarly, when the browser is closed, the server will perceive

Startup code:

public static void main(String[] args) throws InterruptedException {
    NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
    NioEventLoopGroup workerGroup = new NioEventLoopGroup();
    try{
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    //Because it is based on Http protocol, we should use Http encoder and decoder
                    pipeline.addLast(new HttpServerCodec());
                    //It is written in block mode, and the ChunkedWriter processor is added
                    pipeline.addLast(new ChunkedWriteHandler());
                    /**
                    * 1,http Data is split during transmission, and HttpObjectAggregator can aggregate multiple segments
                    * 2,This is why when a browser sends a large amount of data, it will issue multiple http requests
                    */
                    pipeline.addLast(new HttpObjectAggregator(8192));

                    /**
                    * 1,For websocket, its data is transmitted in the form of frames
                    * 2,You can see that there are six subclasses under the WebsocketFrame
                    * 3,When requested by the browser: ws://localhost:7000/hello indicates the uri of the request
                    * 4,WebSocketServerProtocolHandler The core function is to upgrade http protocol to ws protocol and maintain long connection
                    * 5,Upgrading from Http protocol to Websocket protocol is switched through StatusCode 101 (Switching Protocols).
                    */
                    pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));

                    //Custom Handler to handle business logic
                    pipeline.addLast(new MyTextWebSocketFrameHandler());
                }
            });
        ChannelFuture sync = serverBootstrap.bind(7000).sync();
        sync.channel().closeFuture().sync();
    } finally {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

Handler

//TextWebSocketFrame represents a text frame
public class MyTextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {

        System.out.println("The server received a message"+msg.text());

        //Reply message
        ctx.channel().writeAndFlush(new TextWebSocketFrame("Server time"+ LocalDateTime.now()+" "+msg.text()));
    }

    //This method is triggered when the web client connects
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //id is a unique value, LongText is unique, and shortText is not unique
        System.out.println("handlerAdded Called"+ctx.channel().id().asLongText());
        System.out.println("handlerAdded Called"+ctx.channel().id().asShortText());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handlerRemoved Called"+ctx.channel().id().asLongText());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("Abnormal occurrence"+cause.getMessage());
        ctx.close();
    }
}

14. Case summary

Create startup class:

  • First initialize two nioeventloopgroups. BossGroup generally sets the thread to 1
  • Initialize a ServerBootStrap class. And call it to set many parameters.
    • group(): set two groups for the server and one group for the client
    • chnnel(): the server passes in NioServerSocketChannel and the client passes in NioSocketChannel
    • option(): the server sets so to BossGroup_ Backlog task queue size
    • childOption(): the server sets the connection so for the WorkerGroup_ Keepalive keep connected
    • handler(): the server sets handler for BossGroup and the client sets handler
    • childHandler(): the server sets the Handler for the WorkerGroup.
  • Bind the port through BootStrap and listen for shutdown events. Set to sync

Handler:

  • SimpleChannelInboundHandler: it can be inherited to handle many communications. After the deliberation of the above cases, it is common to write your own Handler to inherit it
  • ChannelInboundHandlerAdapter: This is the parent class of the previous one. We can judge the connection status by inheriting its userEventTriggered during heartbeat detection. We can also inherit this trigger through the simple above
  • IdleStateHandler: during heartbeat detection, we need to trigger the above trigger through this Handler
  • HttpServerCodec: provides good for Http encoding and decoding, which is generally used for Http requests
  • ChunkedWriteHandler: provide a good Handler, write in block mode, and add a ChunkedWriter processor, which is generally used to send large files.
  • HttpObjectAggregator: it aggregates http data and sends it together
  • WebSocketServerProtocolHandler: pass in the ws path and upgrade the Http protocol to ws protocol

Communication data entity in Netty:

  • TextWebSocketFrame: This is used when websocket is connected. It represents a text frame and is the data form of websocket communication
  • HttpObject: This is used when establishing an Http connection. It can be converted into an HttpRequest

Common methods of handler:

Method nameintroduce
channelRead0(ChannelHandlerContext channelHandlerContext, T t)Read the data and forward the message
handlerAdded(ChannelHandlerContext ctx)The connection is established. Once the connection is established, it is executed first
channelActive(ChannelHandlerContext ctx)Indicates that the channel is active and prompts xxx to go online
channelInactive(ChannelHandlerContext ctx)Indicates that the channel is inactive, prompting xxx to go offline
handlerRemoved(ChannelHandlerContext ctx)Indicates that the channel is disconnected and pushes xx customer's departure information to the current online customer
exceptionCaught(ChannelHandlerContext ctx, Throwable cause)How to handle errors
userEventTriggered(ChannelHandlerContext ctx, Object evt)Event trigger: judge what event happened by judging the type of evt, and then judge the type of event through the attributes inside. We add a trigger after IdleStateHandler to detect heartbeat.

Keywords: Java Netty network

Added by Sandip on Mon, 07 Feb 2022 23:52:28 +0200