Netty Custom Encoding Decoder
Enter the stack:InboundHandler
, out of the stack:OutboundHandler
. Netty buildchain
to handle business.
Customize a decoder
The decoder mainly decodes the messages sent by the client, so it is aStacked processor, so it will have a stack entry markibound=true;
Generally, we will implement our own decoding logic by the base-level Netty ->This is the decoding abstract class. By default, we want to implement an abstract method
#decode
This method has about three parameters;
-
ChannelHandlerContext channelHandlerContext
This is context information, can be obtainedaisle、pipelineetc. -
ByteBuf byteBuf
The message sent by the client is that the object with this parameter is what we want to pass through.read***
The method reads the data type we need, which can beLong
,Byte
Then we can convert data of the same type into the format we need. -
List<Object> list
Collection, passing the decoded data to the nextinboundHandler
Processing class.
Code Example
@Override protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) { // Long => 8 byte if (() >= 8) { (()); } else ("Byte number exception => {}", ()); }
This way we implement a simple decoder.
Customize an encoder
The decoder mainly encodes the messages to be sent to the client by the server, so it is aStacked processor, so it will have a stack entry markoutbound=true;
Using the abstract class provided by Netty =><T>
Generic T represents the type of message you want to send, implementing abstract method =>#encode
There are three parameters of the method:
-
ChannelHandlerContext channelHandlerContext
This is context information, can be obtainedaisle、pipelineetc. -
Long msg
Messages to be sent to the client on the server ByteBuf byteBuf
Code Example
@Override protected void encode(ChannelHandlerContext channelHandlerContext, Long msg, ByteBuf byteBuf) { (msg); ("Send message successfully"); }
Follow-up ->
ByteToMessage
In fact, you will encounter some problems during use, such as:
When our decoder wants to convert bytes into oneInteger
, we knowInteger
It is four bytes, but if there are not enough four bytes when reading, we need to do some judgment logic =>if (() >= 4)
When the return value istrue
When I can continue to execute the decoding logic.
So how can we skip this step and directly carry out our transformation logic without judging?
You can use Netty's
The principle of not judging the number of readable bytes:
ReplayingDecoder
yesByteToMessage
The subclass of the source code is as follows:
public abstract class ReplayingDecoder<S> extends ByteToMessageDecoder { ... }
ReplayingDecoder
The secret is rightByteToMessage
ofCallDecode(...)
Rewriting the method, let’s take a look at the specific implementation:
@Override protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { (in); try { while (()) { int oldReaderIndex = checkpoint = (); int outSize = (); if (outSize > 0) { fireChannelRead(ctx, out, outSize); (); // Check if this handler was removed before continuing with decoding. // If it was removed, it is not safe to continue to operate on the buffer. // // See: // - /netty/netty/issues/4635 if (()) { break; } outSize = 0; } S oldState = state; int oldInputLength = (); try { decodeRemovalReentryProtection(ctx, replayable, out); // Check if this handler was removed before continuing the loop. // If it was removed, it is not safe to continue to operate on the buffer. // // See /netty/netty/issues/1664 if (()) { break; } if (outSize == ()) { if (oldInputLength == () && oldState == state) { throw new DecoderException( (getClass()) + ".decode() must consume the inbound " + "data or change its state if it did not decode anything."); } else { // Previous data has been discarded or caused state transition. // Probably it is reading on. continue; } } } catch (Signal replay) { (REPLAY); // Check if this handler was removed before continuing the loop. // If it was removed, it is not safe to continue to operate on the buffer. // // See /netty/netty/issues/1664 if (()) { break; } // Return to the checkpoint (or oldPosition) and retry. int checkpoint = ; if (checkpoint >= 0) { (checkpoint); } else { // Called by cleanup() - no need to maintain the readerIndex // anymore because the buffer has been released already. } break; } if (oldReaderIndex == () && oldState == state) { throw new DecoderException( (getClass()) + ".decode() method must consume the inbound data " + "or change its state if it decoded something."); } if (isSingleDecode()) { break; } } } catch (DecoderException e) { throw e; } catch (Exception cause) { throw new DecoderException(cause); } }
Implementing logic that does not require judgment is because
int oldReaderIndex = checkpoint = ();
If an exception occurs during execution, it will be reset in the codeindex
Summarize
AlthoughReplayingDecoder
It saves the logic of judgment, but from the implementation logic of his code, it is seen that it is constantly retrying by throwing exceptions, so in some special cases it will cause performance degradation. So when choosing again, you should judge whether to use it according to your actual needsByteToMessage
Or useReplayingDecoder
。
The above is personal experience. I hope you can give you a reference and I hope you can support me more.