Netty之Codec的Decoders和Encoders概述

 A codec is made up of two parts: 

  • Decoder 

  • Encoder 

This  should  make  it  clear  that  the  decoder  is  for  inbound  and  the  encoder  is  for  outbound data. 


Decoder(解码器)

Netty provides a rich set of abstract base classes that help you easily write decoders. These are divided into different types: 

  • Decoders that decode from bytes to message(把字节解码为消息) 

  • Decoders that decode from message to message(把消息解码为另一种格式的消息) 

  • Decoders that decode from message to bytes(把消息解码为字节) 

Lets  define  what  the decoders responsibility(责任) is. A decoder is responsible for decoding inbound data from one format to  another  one.  Because  a  decoder handles  inbound  data,  its  an  abstract  implementation  of ChannelInboundHandler. 


>>ByteToMessageDecoder>>

ByteToMessageDecoder中抽象方法decode()

    /**
     * Decode the from one {@link ByteBuf} to an other. This method will be called till either the input
     * {@link ByteBuf} has nothing to read anymore, till nothing was read from the input {@link ByteBuf} or till
     * this method returns {@code null}.
     *
     * @param ctx           the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
     * @param in            the {@link ByteBuf} from which to read data
     * @param out           the {@link List} to which decoded messages should be added

     * @throws Exception    is thrown if an error accour
     */
    protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;


Often you want to decode from bytes to messages or even from bytes to another sequence of bytes. This is such a common task that Netty ship an abstract base class that you can use to do this. Exactly for this use case ByteToMessageDecoderis provided. Its an abstract base class that lets you write decoders that decode bytes into objects (POJOs) in an easy fashion.

Methods of ByteToMessageDecoder  

  1. decode() :The decode() method is the only abstract method you need to implement. Its called with a ByteBuf that holds all the received bytes and a List into which decoded messages should be added. The decode() method is called as long as it decodes something. 

  2. decodeLast() :Default implementation delegates to decode(). This method is called once, which is when the Channel goes inactive. If you need special handling here you may override decodeLast() to implement it. 


Lets  imagine  we  have  a  stream  of  bytes  written  from  a  remote  peer  to  us,  and  that  it contains  simple  integers.  We  want to  handle  each  integer separately later in  the ChannelPipeline,  so  we  want  to  read  the  integers  from  the  inbound ByteBuf and  pass each integer separately(分别的) to the next ChannelInboundHandler in the ChannelPipeline. 

Netty之Codec的Decoders和Encoders概述_第1张图片

‍‍You  see  in  figure  7.2  that  it  will  read  bytes  from  the  inbound  ByteBuf of  the ToIntegerDecoder, decode them, and write the decoded messages (int this case Integer) to the next ChannelInboundHandler in the ChannelPipeline. The figure also shows each integer will take up four bytes in the ByteBuf. ‍‍


package codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * 把字节转换为int
 * 继承抽象类ByteToMessageDecoder实现解码器
 */
public class ToIntegerDecoder extends ByteToMessageDecoder {

    @Override
    public void decode(ChannelHandlerContext ctx, ByteBuf in,
                       List<Object> out) throws Exception {
        if (in.readableBytes() >= 4) {  // Check if there are at least 4 bytes readable
            out.add(in.readInt());      //Read integer from inbound ByteBuf, add to the List of decodec messages
        }
    }
}


>>MessageToMessageDecoder>>

MessageToMessageDecoder中抽象方法decode()

    /**
     * Decode from one message to an other. This method will be called for each written message that can be handled
     * by this encoder.
     *
     * @param ctx           the {@link ChannelHandlerContext} which this {@link MessageToMessageDecoder} belongs to
     * @param msg           the message to decode to an other one
     * @param out           the {@link List} to which decoded messages should be added
     * @throws Exception    is thrown if an error accour
     */
    protected abstract void decode(ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception;

Methods of MessageToMessageDecoder 

decode() :The decode()method is the only abstract method you need to implement. Its called for each inbound message of the decoder and lets you decode the message in an other message format . The decoded messages are then passed t o the next ChannelInboundHandlerin the ChannelPipeline.

decodeLast() :Default implementation delegates to decode(). decodeLast()is only called one time, which is when the Channelgoes inactive. If you need special handling here you may override decodeLast()to implement it. 


‍‍If you want to decode a message to another type of message,MessageToMessageDecoderis the easiest way to go. The semantic(语义) is quite the same as for all the other decoders I explained before. 

To  illustrate(说明)  some  uses  let  me  give  you  an  example.  Imagine  you  have  integers  and  need  to convert  them  to  a string.  This  should  be  done  as  part  of the ChannelPipeline and implemented as a separate decoder to make it as flexible(灵活) and reusable(可复用的) as possible. 

Figure 7.3 shows the actual logic of the class I want to implement.

Netty之Codec的Decoders和Encoders概述_第2张图片

As it operates on messages and not bytes (in fact, a message can also be of type bytes). The inbound  message  is  directly  passed  in  the  decode()  method  and decoded  messages  will  be added to the List of decoded messages. So the decoder will receive inbound messages, decode them, and add them to the List of decoded  messages.  Once  done  it  will  forward  all  decoded  messages  to  the  next ChannelInboundHandlerin the ChannelPipeline.


该解码器的示例在我的demo中没有成功使用。

看我的demo在http://my.oschina.net/xinxingegeya/blog/282987

package codec;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;

import java.util.List;

public class IntegerToStringDecoder extends MessageToMessageDecoder<Integer> {

    @Override
    public void decode(ChannelHandlerContext ctx, Integer msg,
                       List<Object> out) throws Exception {
        out.add(String.valueOf(msg));
    }
}


Encoder(编码器)

As  a  counterpart  to  the  decoders  Netty  offers,  base  classes  help  you  to  write  encoders  in  an easy way. Again, these are divided into different types: 

  • Encoders that encode from message to message(把消息编码为消息) 

  • Encoders that encode from message to bytes(把消息编码为字节)

Before going deeper, lets define the responsibility of an encoder. An encoder is responsible for encoding outbound data from one format to another. As an encoder handles outbound data, it implements ChanneOutboundHandler. 


>>MessageToByteEncoder>>

MessageToByteEncoder中抽象方法encode()

    /**
     * Encode a message into a {@link ByteBuf}. This method will be called for each written message that can be handled
     * by this encoder.
     *
     * @param ctx           the {@link ChannelHandlerContext} which this {@link MessageToByteEncoder} belongs to
     * @param msg           the message to encode
     * @param out           the {@link ByteBuf} into which the encoded message will be written
     * @throws Exception    is thrown if an error accour
     */
    protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception;


‍‍MessageToByteEncoder is  provided  to  serve  as  an  abstract  base  class  for  your  encoder implementations that need to transform messages back into bytes. 

shows the exact method you need to implement for your encoder, which is named encode

Methods of MessageToByteEncoder 

encode() :The encode()method is the only abstract method you need to implement. Its called with the outbound message, which was received by this encoder and encodes it in a ByteBuf. The ByteBufis then forwarded to the next ChannelOutboundHandlerin the ChannelPipeline. 

Lets see it in action to better understand its usage. Ive written single short values and want to encode them into a ByteBuf to finally send them over the wire. IntegerToByteEncoder is the implementation thats used for this purpose. 

Figure 7.5 shows the logic. 

Netty之Codec的Decoders和Encoders概述_第3张图片

Figure 7.5 shows that it will receive short messages, encode, and write to a ByteBuf. This ByteBuf  is  then  forwarded  to  the  next ChannelOutboundHandler in the ChannelPipeline. As you can also see in figure 7.5, every short will take up 2 bytes in the ByteBuf. 

package codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

public class IntegerToByteEncoder extends MessageToByteEncoder<Short> {
    @Override
    public void encode(ChannelHandlerContext ctx, Short msg, ByteBuf out)
            throws Exception {
        out.writeShort(msg);
    }
}


>>MessageToMessageEncoder>>

MessageToMessageEncoder中抽象方法encode()

    /**
     * Encode from one message to an other. This method will be called for each written message that can be handled
     * by this encoder.
     *
     * @param ctx           the {@link ChannelHandlerContext} which this {@link MessageToMessageEncoder} belongs to
     * @param msg           the message to encode to an other one
     * @param out           the {@link List} into which the encoded msg should be added
     *                      needs to do some kind of aggragation
     * @throws Exception    is thrown if an error accour
     */
    protected abstract void encode(ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception;


Suppose you need a way to encode from one message to another, similar to what you did for inbound data with MessageToMessageDecoder. MessageToMessageEncoder fills  this  gap. 

Shows  the  method  you  need  to implement for your encoder, which is named encode. 

Methods of MessageToMessageEncoder 

encode() :The encode()method is the only abstract method you need to implement. Its called for each message written with write() and encode the message to one or multiple new messages. The encoded messages are then forwarded to the next ChannelOutboundHandler in the ChannelPipeline. 

Again let us look at some example. Imaging you need to encode Integer messages to String messages you could do this easily with MessageToMessageEncoder. 

Figure 7.6 shows the logic. 

Netty之Codec的Decoders和Encoders概述_第4张图片

The  encoder  encode  Integer  messages  and  forward  them  to  the  next ChannelOutboundHandlerin the ChannelPipeline. 

下面这个编码器在一个demo中我试过,demo没运行成功。

看这篇文章http://my.oschina.net/xinxingegeya/blog/282987。原来使用

package codec;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;

import java.util.List;

public class IntegerToStringEncoder extends MessageToMessageEncoder<Integer> {
    @Override
    public void encode(ChannelHandlerContext ctx, Integer msg,
                       List<Object> out) throws Exception {
        out.add(String.valueOf(msg));
    }
}

===========END===========


你可能感兴趣的:(Netty之Codec的Decoders和Encoders概述)