使用Netty的LengthFieldBasedFrameDecoder时,我应该如何处理ASCII值?

时间:2016-03-24 19:38:08

标签: java netty

我正在使用Netty 4.0.33-Final中的LengthFieldBasedFrameDecoder类。

我正在使用的软件可以在没有Netty帮助的情况下与电视进行通信,所以我在这里以非常规的方式使用Netty。我只是使用Netty作为Decoders和Channel Pipeline来解码来自各种不同设备的消息。这至少是我的目标。

我正在处理的电视有一个查询电源的协议命令,电视响应该命令。响应的第一个字节是长度值。

我的软件以字节为单位接收该响应,我想使用Netty对其进行解码。当电视向我的应用程序发送响应时,根据Netty的LoggingHandler,我传递给LengthFieldBasedFrameDecoder的字节看起来像这样......

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 38 30 31 72 6c 30 30 31 0d                      |801rl001.       |
+--------+-------------------------------------------------+----------------+

电视发送给我的第一个字节是长度字段。在此示例中,消息长度为8个字节(不包括长度字段)。

问题是LengthFieldBasedFrameDecoder将长度字段解释为十六进制值0x38并使用十进制值56作为长度而不是预期的8.当然,这是合乎逻辑的,因为十六进制的十进制值数字0x38是56.我认为记录器显示十六进制值0x38的原因是因为ASCII表显示ASCII字符8的十六进制值为0x38。

所以问题是来自电视的消息没有被处理,因为解码器正在等待更多的字节进来以满足它认为完整消息所需的56个字节。

作为一个黑客,我编写了这段代码,将消息的第一个字节转换为LengthBasedFrameDecoder可以正确处理的值。

/**
 * This is where I recieve the raw bytes from the TV
 */
public void receive(byte[] data, int length) {

    // rip the first byte off and make it an int
    int messageLength = Integer.parseInt(new String(data).substring(0, 1));

    // convert the int to a byte
    byte[] firstByte = { (byte) messageLength };

    // replace the original first byte with my newly created one
    data[0] = firstByte[0];

    // create the ByteBuf so that I can write it to my awaiting pipeline
    ByteBuf byteBuf = Unpooled.copiedBuffer(data, 0, length);
    channel.writeAndFlush(byteBuf);
}

我是Netty的新手,所以我希望有一些我缺少的东西可以处理内置于Netty中的这种情况。你能帮我找到合适的方法吗?

2 个答案:

答案 0 :(得分:1)

您可以覆盖LengthFieldBasedFrameDecoder getUnadjustedFrameLength()

的实施
public class CustomLengthFieldBasedFrameDecoder extends LengthFieldBasedFrameDecoder {
  @Override
  protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
    buf = buf.order(order);
    byte[] lengthBytes = new Byte[length];
    buf.getBytes(offset, lengthBytes);
    String s = new String(lengthBytes, CharsetUtil.US_ASCII);
    return Long.parseLong(s);
  }
}

答案 1 :(得分:0)

这个答案与Josh Wilson提供的答案非常相似。

我继续并决定按照他的建议覆盖LengthFieldBasedFrameDecoder的实现。我只使用了较少的代码行。

protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
    try {
        return Long.parseLong(buf.toString(offset, length, charset));
    } catch (NumberFormatException nfe) {
        throw new DecoderException(nfe);
    }
}

编辑:

我意识到我应该发布在扩展LengthFieldBasedFrameDecoder的类的构造函数中完成的工作,所以这里是整个类。

public class StringLengthFieldBasedFrameDecoder extends LengthFieldBasedFrameDecoder {
    private Charset charset;
    public StringLengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {
        this(maxFrameLength, lengthFieldOffset, lengthFieldLength, 0, 0);
    }

    public StringLengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,
            int lengthAdjustment, int initialBytesToStrip) {
        this(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, true);
    }

    public StringLengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,
            int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
        this(ByteOrder.BIG_ENDIAN, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment,
                initialBytesToStrip, failFast, Charset.forName("US-ASCII"));
    }

    public StringLengthFieldBasedFrameDecoder(ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset,
            int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast, Charset charset) {
        super(byteOrder, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip,failFast);
        this.charset = charset;
    }

    protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
        try {
            return Long.parseLong(buf.toString(offset, length, charset));
        } catch (NumberFormatException nfe) {
            throw new DecoderException(nfe);
        }
    }
}