在Netty 4 MessageToMessageDecoder中解码具有可变长度的消息

时间:2014-12-12 11:01:21

标签: java netty

如何在 Netty 4 中正确解码具有可变长度的多条消息?目前我的消息正由解码器合并为一个。有没有办法正确分割它们?

我在 MessageToMessageDecoder 中使用此解码方法。

@Override
protected void decode(final ChannelHandlerContext paramChannelHandlerContext,
            final ByteBuf message, final List<Object> out) throws Exception {
    byte[] array = new byte[message.nioBuffer().remaining()];
    message.getBytes(0, array);
    out.add(new NettyMessage(array));
}

编码消息的方法转换为 MessageToMessageEncoder 中的字节。

@Override
protected void encode(final ChannelHandlerContext ctx, final NettyMessage message,
        final List<Object> out) throws Exception {
    out.add(message.payload);
}

这是我的 NettyMessage 类。

public class NettyMessage {
    public byte[] payload;

    public NettyMessage(final byte[] array) {
        this.payload = array;
    }
}

我使用的是Netty 4.0.23。

2 个答案:

答案 0 :(得分:2)

实际上我必须实施 MessageToByteEncoder ByteToMessageDecoder 。作为编码器,我在头部使用了有效载荷长度的简单实现。

public class IntegerHeaderFrameEncoder extends MessageToByteEncoder<byte[]> {
    @Override
    protected void encode(final ChannelHandlerContext paramChannelHandlerContext,
            final byte[] msg, final ByteBuf out) throws Exception {
        out.writeInt(msg.length);
        out.writeBytes(msg);
    }
}

作为解码器,我使用 ReplayingDecoder 来简化实施。

public class IntegerHeaderFrameDecoder extends ReplayingDecoder<Void> {
    @Override
    protected void decode(final ChannelHandlerContext ctx, final ByteBuf buf,
            final List<Object> out) throws Exception {
        out.add(buf.readBytes(buf.readInt()));
    }
}

然后将两者都添加到渠道管道。

pipeline.addLast(new IntegerHeaderFrameDecoder());
pipeline.addLast(new IntegerHeaderFrameEncoder());
pipeline.addLast(new NettyMessageDecoder());
pipeline.addLast(new NettyMessageEncoder());

答案 1 :(得分:2)

听起来你会发现LengthFieldBasedFrameDecoder很有用。您可以指定长度指示符的位置以及它的字节数,以及一些其他有用的功能,例如剥离标题。

public LengthFieldBasedFrameDecoder(
        int maxFrameLength,
        int lengthFieldOffset, int lengthFieldLength,
        int lengthAdjustment, int initialBytesToStrip)

从文档中摘录:

A decoder that splits the received ByteBufs dynamically by the value of the length field in
the message. It is particularly useful when you decode a binary message which has an
integer header field that represents the length of the message body or the whole message.

The value of the length field in this example is 12 (0x0C) which represents the length of
"HELLO, WORLD". By default, the decoder assumes that the length field represents the 
number of the bytes that follows the length field. Therefore, it can be decoded with the
simplistic parameter combination.

 lengthFieldOffset   = 0
 lengthFieldLength   = 2
 lengthAdjustment    = 0
 initialBytesToStrip = 0 (= do not strip header)

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