Netty 10 Codec framework

Source: Internet
Author: User
Tags readable

Encoding and decoding, or the conversion of data from one specific protocol format to another format. These tasks are handled by components that are commonly referred to as codecs. Netty provides a variety of components that simplify the process of creating a custom codec to support a wide range of protocols. For example, if you are building a Netty-based mail server, you will find that Netty's support for codecs is invaluable for implementing POP3, IMAP, and SMTP protocols.

1. What is a codec

Each network application must define how to resolve the raw bytes that are transferred back and forth between two nodes, and how to convert the data format of the target application to each other. This conversion logic is handled by the codec, which consists of encoders and decoders, each of which can convert a byte stream from one format to another.

If you treat a message as a structured sequence of bytes that has a specific meaning for a particular application-its data. The encoder then converts the message into a format that is appropriate for transmission (most likely a byte stream), while the corresponding decoder is the message format for exchanging network bytes back into the application. Therefore, the encoder operates the outbound data, and the decoder processes the inbound data.

2. Decoder

--Decodes bytes into messages--bytetomessagedecoder and Replayingdecoder

--Decoding one message type to another--messagetomessagedecoder

Because the decoder is responsible for converting inbound data from one format to another, it is not surprising to know that the Netty decoder implements Channelinboundhandler.

This is used whenever the inbound data needs to be converted for the next channelinboundhandler in Channelpipeline. In addition, thanks to the channelpipeline design, multiple decoders can be chained together to implement any complex conversion logic, which is also an example of how Netty supports the modularity and reuse of code.

3. Abstract class Bytetomessagedecoder

Decoding a byte to a message is such a common task that Netty provides him with an abstract base class: Bytetomessagedecoder. Since you cannot know whether a remote node will send a complete message at once, the class will buffer inbound data.

Here's an example of how to use this class, assuming you receive a byte stream containing a simple int, each int needs to be handled separately. In this case, you need to read each int from the inbound bytebuf and pass it to the next Channelinboundhandler in Channelpipeline. In order to decode this byte stream, you want to extend the Bytetomessagedecoder class. (It is important to note that the original type int is automatically boxed as an integer when added to the list, as shown in the following design diagram.) Each time you read 4 bytes from the inbound bytebuf, decode it to an int, and then add it to a list. When no more elements can be added to the list, its contents will be sent to the next channelinboundhandler.

 public class tointegerdecoder extends  bytetomessagedecoder{ @Override protected void Decode (channelhandlercontext channelhandlercontext, ByteBuf in, list<object> out" throws exception {//check if there is at least 4 bytes readable (byte length of an int) if (in.readablebytes () >= 4) {/ /reads an int from the inbound bytebuf and adds it to the list of decoded messages Out.add (In.readint ()); } }} 

While Bytetomessagedecoder makes it easy to implement this pattern, you might find it a bit cumbersome to verify that the input bytebuf has enough data before calling the Readint () method.

4. Abstract class Replayingdecoder

Replayingdecoder extends the Bytetomessagedecoder class so that we do not have to call the Readablebytes () method. It implements this by using a custom BYTEBUF implementation, REPLAYINGDECODERBYTEBUF, wrapping the incoming bytebuf, which will execute the call internally.

Public abstract class Replayingdecoder extends Bytetomessagedecoder

The type parameter s specifies the type to use for state management, where void represents no need for state management. The following code shows the re-implementation of Tointegerdecoder based on Replayingdecoder.

class ToIntegerDecoder2 extends ReplayingDecoder<Void>{ @Override protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> out) throws Exception { out.add(in.readInt()); }}

As before, the int extracted from BYTEBUF will be added to the list, and if there are not enough bytes available, the implementation of the Readint () method will throw an error, which will be captured and processed in the base class. When more data is available for reading, the decode () method will be called again.

Please note the following aspects of REPLAYINGDECODERBYTEBUF:

--Not all BYTEBUF operations are supported, and if an unsupported method is called, a unsupportedoperationexception will be thrown

--replayingdecoder slightly slower than Bytetomessagedecoder

--If using bytetomessagedecoder does not introduce too much complexity, then use it; otherwise, use the Replayingdecoder

5. Abstract class Messagetomessagedecoder

Public abstract class Messagetomessagedecoder extends Channelinboundhandleradapter

Type parameter I specifies the type of the input parameter msg for the decode () method, which is the only method that you must implement.

In this example, we will write a Integertostringdecoder decoder to extend the messagetomessagedecoder. Its decode () method converts the integer argument to its string representation and will have the following signature:

public void decode (Channelhandlercontext ctx, Integer msg, List out) throws Exception

As before, the decoded string will be added to the outgoing list and forwarded to the next Channelinboundhandler

class IntegerToStringDecoder extends MessageToMessageDecoder<Integer>{ @Override protected void decode(ChannelHandlerContext channelHandlerContext, Integer msg, List<Object> out) throws Exception { //将Integer消息转换为它的String表示,并将其添加到输出的List中 out.add(String.valueOf(msg)); }}

6, Toolongframeexception class

Because Netty is an asynchronous framework, it is necessary to buffer them in memory before the bytes can be decoded, so the decoder cannot buffer large amounts of data so that the available memory is exhausted. To relieve this common concern, Netty provides the Toolongframeexception class, which will be thrown by the decoder when the frame exceeds the specified size limit.

To avoid this, you can set a maximum number of bytes for the cut value, and if it exceeds, it will cause a toolongframeexception to be thrown, and how to handle the exception depends entirely on the user of the decoder. Some protocols (HTTP) may allow you to return a special response, whereas in other cases, the only option might be to close the corresponding connection.

The following code shows how Bytetomessagedecoder uses Toolongframeexception to notify other Channelhandler in Channelpipeline that a frame size overflow has occurred. It is important to note that if you are using a variable frame size protocol, this protection will be of particular importance.

PublicClassSafebytetomessagedecoderExtendsbytetomessagedecoder{private staticFinal intMax_frame_size =1024;  @Override protected void decode ( Channelhandlercontext Channelhandlercontext, bytebuf in, List<< Span class= "Hljs-type" >object> out) throws Exception {int readable = In.readablebytes (); //check if there are more than max_frame_size bytes in the buffer if (Readable > max_frame_size) {//skips all readable bytes, throws toolongframeexception and notifies Channelhandler In.skipbytes (readable); throw new TooLongFrameException ( Span class= "hljs-string" > "Frame too big!");} //do Something}            

7. Abstract class Messagetobyteencoder

This class has only one method, and the decoder has two. The reason is that the decoder usually needs to produce the last message after the channel is closed (the Decodelast () method), which obviously does not apply to the encoder scene-it is meaningless to still produce a message after the connection is closed.

Shorttobyteencoder, which takes an instance of a short type as a message, encodes it to the original type value of short, and writes it to the BYTEBUF, It will then be forwarded to the next Channeloutboundhandler in Channelpipeline. Each outgoing short value will consume 2 bytes in bytebuf.

class ShortToByteEncoder extends MessageToByteEncoder<Short>{ @Override protected void encode(ChannelHandlerContext channelHandlerContext, Short msg, ByteBuf out) throws Exception { //将Short写入ByteBuf中 out.writeShort(msg); }}

Netty provides a number of specialized messagetobyteencoder that you can implement on their own encoders. The Websocket08frameencoder class provides a good example. You can find it in the Io.netty.handler.codec.http.websocket package.

8. Abstract class Messagetomessageencoder

We will show how outbound data will be encoded from one message to another. The encoder () method of the Messagetomessageencoder class provides this capability.

The following code, the encoder adds a string representation of each outbound integer to the list.

class IntegerToStringEncoder extends MessageToMessageEncoder<Integer>{ @Override protected void encode(ChannelHandlerContext channelHandlerContext, Integer msg, List<Object> out) throws Exception { //将Integer转换为String,并将其添加到List中 out.add(String.valueOf(msg)); }}

9. Abstract Codec class

It is useful to manage the conversion of inbound and outbound data and messages in the same class. Netty's abstract codec class is just for this purpose, because each of them will bundle a decoder/encoder pair to handle the two types of operations we've been learning.

By separating the two functions as much as possible, maximizing the reusability and extensibility of the code is a fundamental principle of the netty design.

10. Abstract class Bytetomessagecodec

Scenario: We need to encode the byte into some form of message, possibly Pojo, and then encode it again. BYTETOMESSAGECODEC will handle all this for us because it combines bytetomessagedecoder and his reverse messagetobyteencoder.

Any request/response protocol can be an ideal choice for using BYTETOMESSAGECODEC, for example, in an implementation of an SMTP, the codec reads the incoming bytes and decodes them into a custom message type, such as Smtprequest. On the receiving side, when a response is created, a smtpresponse is generated that will be encoded back into bytes for transmission.

11, Combinedchannelduplexhandler Class

The combination of a decoder and an encoder can have an impact on reusability. However, there is a way to avoid this penalty without sacrificing the convenience of having a decoder and an encoder as a single unit deployment. Combinedchannelduplexhandler provides this solution, which is declared as:

public class Combinedchannelduplexhandler <i extends Channelinboundhandler, O extends channeloutboundhandler>

This class acts as a container for Channelinboundhandler and Channeloutboundhandler (type parameters I and O for this class). By providing types that inherit both the decoder class and the encoder class, we can implement a codec without having to extend the abstract codec class directly.

First, let's look at the Bytetochardecoder in the code. Note that the implementation extends Bytetomessagedecoder because it is going to read characters from the bytebuf.

class ByteToCharDecoder extends ByteToMessageDecoder{ @Override protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> out) throws Exception { while (in.readableBytes() >= 2){ //将一个或者多个Character对象添加到传出的List中 out.add(in.readChar()); } }}

The decode () method here extracts 2 bytes from the bytebuf at a time and writes them as Char to the list, which is automatically boxed as a character object.

The following code, which contains Chartobyteencoder, can convert character back to bytes. This class extends the Messagetobyteencoder because it requires the encoding of char messages into bytebuf, which is done directly by writing to Bytebuf.

class CharToByteEncoder extends MessageToByteEncoder<Character>{ @Override protected void encode(ChannelHandlerContext channelHandlerContext, Character msg, ByteBuf out) throws Exception { //将Character解码为char,并将其写入到出站ByteBuf中 out.writeChar(msg); }}

Now that we have decoders and encoders, we'll combine them to build a codec. As shown in the following code.

In some cases, combining implementations in this way may be simpler and more flexible than the way the codec classes are used.

Netty 10 Codec framework

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.