Make writing a habit together! This is the 7th day of my participation in the “Gold Digging Day New Plan · April More text Challenge”. Click here for more details.

Introduction to the

Data in netty is transmitted through ByteBuf. A ByteBuf may contain multiple meaningful data, which can be called frames. That is, a ByteBuf can contain multiple frames.

For the receiver of the message, after receiving ByteBuf and parsing useful data from ByteBuf, the frame in ByteBuf needs to be split and parsed.

In general, there are special delimiters between different frames. These delimiters can be used to distinguish frames from each other for data parsing.

Netty provides us with some suitable frame decoders, which can be used to simplify our work. Here are some common frame decoders in Netty:

Let’s take a closer look at the use of the frame decoders.

LineBasedFrameDecoder

LineBasedFrameDecoder by name means frame by line. Depending on the operating system, a newline can have two newlines, “\n” and “\r\n”.

The basic principle of LineBasedFrameDecoder is to read the corresponding characters from ByteBuf and compare them with “\n” and “\r\n”. These frameDecoder also have certain encoding requirements, generally utF-8 encoding is required. Since “\n” and “\r” appear in a single byte in such encodings and are not used in other combinative encodings, it is very safe to use “\n” and “\r” for judgment.

LineBasedFrameDecoder has several important properties. One is the maxLength property, which detects the length of the received message and throws a TooLongFrameException exception if the length limit is exceeded.

There is also a stripDelimiter attribute to determine whether delimiter needs to be filtered out.

The other is failFast. If this value is true, TooLongFrameException will be thrown whenever the length of the frame exceeds maxFrameLength, regardless of whether the frame has been read. If this value is false, TooLongFrameException will be thrown after the entire frame has been read.

The core logic of LineBasedFrameDecoder is to find the position of the line separator and then read the corresponding frame information based on that position.

    private int findEndOfLine(final ByteBuf buffer) {
        int totalLength = buffer.readableBytes();
        int i = buffer.forEachByte(buffer.readerIndex() + offset, totalLength - offset, ByteProcessor.FIND_LF);
        if (i >= 0) {
            offset = 0;
            if (i > 0 && buffer.getByte(i - 1) == '\r') {
                i--;
            }
        } else {
            offset = totalLength;
        }
        return i;
    }
Copy the code

ByteBuf is traversed by a forEachByte of ByteBuf. The character we are looking for is: byteprocessor.find_lf.

Finally, the object decoded by LineBasedFrameDecoder is a ByteBuf.

DelimiterBasedFrameDecoder

The LineBasedFrameDecoder is only valid for line separators. If our frame is separated by other separators, the LineBasedFrameDecoder will not be used. So netty provides a more general DelimiterBasedFrameDecoder, this frameDecoder can custom delimiter:

public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {

        public DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf delimiter) {
        this(maxFrameLength, true, delimiter);
    }

Copy the code

Delimiter is passed in as a ByteBuf, so DELIMiter may be more than one character.

In order to solve this problem in DelimiterBasedFrameDecoder defines a ByteBuf array:

    private final ByteBuf[] delimiters;

    delimiters= delimiter.readableBytes();
Copy the code

This delimiters is obtained by calling Delimiter’s readableBytes.

DelimiterBasedFrameDecoder logic and LineBasedFrameDecoder about, is by comparing the bufer to intercept the data in the bufer the character, But DelimiterBasedFrameDecoder can accept multiple delimiters, so its use will be based on broad.

FixedLengthFrameDecoder

In addition to ByteBuf character comparison for frame splitting, there are some other common frame splitting methods, such as by specific length, Netty provides a frame splitting decoder called FixedLengthFrameDecoder.

public class FixedLengthFrameDecoder extends ByteToMessageDecoder 
Copy the code

A FixedLengthFrameDecoder is also derived from ByteToMessageDecoder, which is very simple to define and can pass in the length of a frame:

    public FixedLengthFrameDecoder(int frameLength) {
        checkPositive(frameLength, "frameLength");
        this.frameLength = frameLength;
    }
Copy the code

ByteBuf’s readRetainedSlice method is then called to read fixed-length data:

in.readRetainedSlice(frameLength)
Copy the code

Finally, the read data is returned.

LengthFieldBasedFrameDecoder

Other frames contain a length field that indicates how much data is readable in the ByteBuf, called LengthFieldBasedFrame.

Netty also provides a corresponding processing decoder:

public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder 
Copy the code

The logic of reading is simple: first read the length, then read the data based on the length. In order to achieve this logic, LengthFieldBasedFrameDecoder provides four fields, LengthFieldOffset, lengthFieldLength lengthAdjustment and initialBytesToStrip.

LengthFieldOffset specifies the start position of the length field, lengthFieldLength defines the length field, and lengthFieldLength adjustment specifies the adjustment of lengthFieldLength. Initialbyteststrip Indicates whether to remove the length field.

This may sound confusing, but let’s take a few examples, starting with the simplest:

   BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
   +--------+----------------+      +--------+----------------+
   | Length | Actual Content |----->| Length | Actual Content |
   | 0x000C | "HELLO, WORLD" |      | 0x000C | "HELLO, WORLD" |
   +--------+----------------+      +--------+----------------+
Copy the code

The message to be encoded has a length field, followed by the actual data, and 0x000C is a hexadecimal number representing 12, the length of the string in “HELLO, WORLD”.

The values of the four attributes are:

   lengthFieldOffset   = 0
   lengthFieldLength   = 2
   lengthAdjustment    = 0
   initialBytesToStrip = 0 
Copy the code

The length field starts at 0 and takes up two bytes. The length does not need to be adjusted, nor does the field need to be adjusted.

Let’s look at a more complex example where the four attributes are as follows:

   lengthFieldOffset   = 1  
   lengthFieldLength   = 2
   lengthAdjustment    = 1  
   initialBytesToStrip = 3  
Copy the code

The corresponding encoding data is as follows:

BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
   +------+--------+------+----------------+      +------+----------------+
   | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
   | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
   +------+--------+------+----------------+      +------+----------------+
Copy the code

In the example above, the length field starts from the first byte (the 0th byte is HDR1). The length field takes up 2 bytes. Adjust the length by one byte, and the final data position is 1+2+1=4.

conclusion

Netty provides several frame decoders based on character set to basically meet our daily work needs. Of course, if you are transferring more complex objects, you can consider custom codecs and decoders. The custom logic steps are the same as we explained above.

This article is available at www.flydean.com/14-5-netty-…

The most popular interpretation, the most profound dry goods, the most concise tutorial, many tips you didn’t know waiting for you to discover!

Welcome to pay attention to my public number: “procedures those things”, understand technology, more understand you!