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

Introduction to the

We know that data is transmitted in Netty in the form of ByteBuf, which is the basis of data transmission in Netty. But for modern applications, we often need to use other data structures or types.

To facilitate our programming, one way is for the programmer to convert the data format when it is passed into Netty, and then call Netty’s system methods. Another way is to define coDecs that automatically convert the data format used in the program to ByteBuf using Netty’s built-in encoding mechanism.

It is clear that using CODEC is much simpler and more consistent with the development rules of the application.

To facilitate the development of the program, Netty has internally defined some core Codec plug-ins that we can use when we need them.

This article will explain netty internal implementation of CODEC and a core encoder base64.

Netty Codec implementation logic

The purpose of all Netty Codec is to convert data types during transmission, in other words, to process data. We know there are two in netty data handler class that is ChannelInboundHandlerAdapter and ChannelOutboundHandlerAdapter respectively, They are processed respectively for inbound and outbound messages in a channel.

So naturally, our CODEC logic only needs to be added in these two places.

Netty provides two inherited HandlerAdapter classes, MessageToMessageDecoder and MessageToMessageEncoder:

public abstract class MessageToMessageEncoder<I> extends ChannelOutboundHandlerAdapter 

public abstract class MessageToMessageDecoder<I> extends ChannelInboundHandlerAdapter
Copy the code

As the name suggests, these two classes are used for encoding and decoding separately, so our coDEC only needs to implement these two classes separately.

Here is an example of stringToInt decoder and IntegerToStringEncoder:

public class StringToIntegerDecoder extends MessageToMessageDecoder<String> { @Override public void decode(ChannelHandlerContext ctx, String message, List<Object> out) throws Exception { out.add(message.length()); }}Copy the code
public class IntegerToStringEncoder extends MessageToMessageEncoder<Integer> { @Override public void encode(ChannelHandlerContext ctx, Integer message, List<Object> out) throws Exception { out.add(message.toString()); }}Copy the code

The simplest implementation is to refactor the decode and encode methods of the two classes, respectively.

Netty Base64 implementation

We know that a utility class called java.util.base64 already has a Base64 implementation in the JDK. But in netty and USES a new implementation class is also called Base64, ty. It is the full name of io.net handler. Codec. Base64. Base64.

The Base64 class uses a Base64Dialect class, which is the Base64 dialect encoding that is supported by Base64 in Netty. The following types are available in Base64Dialect:

STANDARD
URL_SAFE
ORDERED
Copy the code

STANDARD corresponds to RFC3548, which is also the STANDARD Base64 in JDK. URL_SAFE corresponds to the BASE64URL version in RFC3548, which corresponds to getUrlEncode in JDK.

The last one is ORDERED, which stands for RFC1940, and this encoding implementation is not available in the JDK.

Why does Netty need to create a Base64 utility class when it already exists in the JDK?

Consider the Base64 scenario in Netty, where we typically add custom coding to handlers that handle data streams.

The Base64 implementation in the JDK is fine for fixed-length data, but less efficient when applied to data streams. That’s why Netty needs to re-implement a Base64 class for Streaming data.

The implementation in Netty uses Robert Harder’s Public Domain Base64 Encoder/Decoder. I’m not going to go into the logic of this algorithm. Interested friends can explore on their own.

Base64 provides a method to encode and decode ByteBuf in Base64. We choose the method with the longest parameter to observe, as shown below:

    public static ByteBuf encode(
            ByteBuf src, int off, int len, boolean breakLines, Base64Dialect dialect, ByteBufAllocator allocator)

    public static ByteBuf decode(
            ByteBuf src, int off, int len, Base64Dialect dialect, ByteBufAllocator allocator)
Copy the code

For the encode method, the following parameters are required:

  1. SRC of type ByteBuf, which is the source we need to code.
  2. The off and len types of int indicate the location in ByteBuf to encode data.
  3. Boolean breakLines, indicating whether to add a newline character.
  4. Dialect of the Base64Dialect type, which indicates the selected Base64 encoding type.
  5. ByteBufAllocator Allocator, which indicates the generation mode of returned ByteBuf.

The same Decode method requires the following parameters:

  1. SRC of type ByteBuf, which is the source we need to decode.
  2. The off and len types of int indicate the location of the data to be decoded in ByteBuf.
  3. Dialect of the Base64Dialect type, which indicates the selected Base64 encoding type.
  4. ByteBufAllocator Allocator, which indicates the generation mode of returned ByteBuf.

Base64 encoding and decoder in NetTY

We just introduced the new Base64 utility class available in Netty, which provides methods for encoding and decoding data in ByteBuf. Let’s take a look at how Netty uses this utility class to implement the Base64 encoding and decoder in Netty.

Netty provides Base64 encoding and decoder, which are Base64Encoder and Base64Decoder respectively. First, let’s look at the basic use of Base64 encoding decoder:

ChannelPipeline pipeline = ... ; // Decoders pipeline.addLast("frameDecoder", new DelimiterBasedFrameDecoder(80, Delimiters.nulDelimiter())); pipeline.addLast("base64Decoder", new Base64Decoder()); // Encoder pipeline.addLast("base64Encoder", new Base64Encoder());Copy the code

It’s easy to use, just add Base64Decoder and Base64Encoder to pipeline.

Sometimes Base64Decoder need and DelimiterBasedFrameDecoder used together, especially in the TCP/IP protocol, because we need according to the specific Delimiters ByteBuf should be divided into several frames. Only in this way can the data be valid.

Base64Encoder

First, let’s look at the encoder of Base64. The realization of Base64Encoder is relatively simple. First, let’s look at the definition of Base64Encoder:

public class Base64Encoder extends MessageToMessageEncoder<ByteBuf> 
Copy the code

Base64Encoder inherits from MessageToMessageEncoder. It passes in the generic ByteBuf, which means that ByteBuf is encoded as ByteBuf, although the external ByteBuf type is unchanged. But the data in ByteBuf is already encoded as Base64.

Next comes the Base64Encoder constructor:

    public Base64Encoder(boolean breakLines, Base64Dialect dialect) {
        this.dialect = ObjectUtil.checkNotNull(dialect, "dialect");
        this.breakLines = breakLines;
    }
Copy the code

The Base64Encoder can accept two parameters, breakLines and Base64Dialect for whether there are newlines or not.

Its encode method is also simple:

    protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
        out.add(Base64.encode(msg, msg.readerIndex(), msg.readableBytes(), breakLines, dialect));
    }
Copy the code

We directly use the encode method of the Base64 utility class we talked about above, and then add the return value to the Out object.

Base64Decoder

Base64Decoder is used to decode ByteBuf base64 encoded content into the original content, first look at the Base64Decoder definition:

public class Base64Decoder extends MessageToMessageDecoder<ByteBuf> 
Copy the code

Base64Decoder inherits MessageToMessageDecoder, passing in the generic ByteBuf.

Let’s take a look at the Base64Decoder constructor:

public Base64Decoder(Base64Dialect dialect) {
        this.dialect = ObjectUtil.checkNotNull(dialect, "dialect");
    }
Copy the code

The Base64Decoder constructor is very simple. Compared to the Base64Encoder, it only needs one argument: Dialect of type Base64Dialect, which indicates the selected base64 decoder decoding method.

Here’s how to decode it:

    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
        out.add(Base64.decode(msg, msg.readerIndex(), msg.readableBytes(), dialect));
    }
Copy the code

The decoding method also calls the Decode method of the Base64 utility class and adds it to the returned Out list.

conclusion

This chapter introduces the core encoder Base64 in Netty, which is responsible for encoding the message in ByteBuf to Base64 format, and provides the corresponding decoder, you can use when you need.

This article is available at www.flydean.com/14-1-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!