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

时间:2022-07-06 20:18:31

I'm using the LengthFieldBasedFrameDecoder class from Netty 4.0.33-Final.

我正在使用来自Netty 4.0.33-Final的lengthfieldframedecoder类。

The software I'm working on can communicate with a TV without the help of Netty, so I'm using Netty in a non conventional way here. I'm just using Netty for the Decoders and the Channel Pipeline to decode messages from all sorts of different devices. That's my goal at least.

我正在开发的软件可以在没有Netty帮助的情况下与电视进行通信,所以我在这里用的是一种非传统的方式。我只是使用Netty进行解码器和通道管道来解码来自各种不同设备的消息。这至少是我的目标。

The TV that I'm currently working on has a protocol command for Query Power, and the TV responds with a response to that command. The response's first byte is a length value.

我目前正在开发的电视机有一个用于查询功能的协议命令,而电视机则响应该命令。响应的第一个字节是长度值。

My software receives that response in bytes, and I'd like to decode it using Netty. When the TV sends my application a response, according to Netty's LoggingHandler the bytes I'm passing on to the LengthFieldBasedFrameDecoder look like this...

我的软件接收的响应以字节为单位,我想用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.       |
+--------+-------------------------------------------------+----------------+

The first byte the TV is sending me is the length field. In this example, the message is 8 bytes long (not including the length field).

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

The problem is that the LengthFieldBasedFrameDecoder is interpreting the length field as a hex value of 0x38 and using the decimal value of 56 as the length instead of the intended 8. Of course, this is logical, because the decimal value of the hex number 0x38 is 56. I think the reason the logger is showing the hex value 0x38 is because the ASCII table shows that an ASCII character of 8 has the hex value of 0x38.

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

So the issue is that the message from the TV does not get processed, because the decoder is waiting for more bytes to come in to fulfill the 56 bytes that it thinks it needs for a complete message.

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

As a hack, I wrote this code to convert the first byte of the message to a value that the LengthBasedFrameDecoder could handle correctly.

我编写了这段代码,将消息的第一个字节转换为lengthedframedecoder能够正确处理的值。

/**
 * 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);
}

I'm new to Netty, so I'm hoping that there is something I'm missing that handles this scenario built into Netty. Can you guys help me find the right way to handle this?

我是Netty的新手,所以我希望在Netty中有一些东西可以处理这个场景。你们能帮我找到解决这个问题的正确方法吗?

2 个解决方案

#1


1  

You can override the implementation of LengthFieldBasedFrameDecoder getUnadjustedFrameLength()

可以覆盖LengthFieldBasedFrameDecoder getunstedframelength()的实现

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);
  }
}

#2


0  

This answer is very similar to the answer provided by Josh Wilson.

这个答案和Josh Wilson给出的答案非常相似。

I went ahead and decided to override the implementation of LengthFieldBasedFrameDecoder as he suggested. I just used fewer lines of code.

我决定按照他的建议重写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);
    }
}

EDIT:

编辑:

I realized that I should post the work that is done in the constructors of the class that is extending the LengthFieldBasedFrameDecoder, so here's the entire class.

我意识到我应该在扩展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);
        }
    }
}

#1


1  

You can override the implementation of LengthFieldBasedFrameDecoder getUnadjustedFrameLength()

可以覆盖LengthFieldBasedFrameDecoder getunstedframelength()的实现

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);
  }
}

#2


0  

This answer is very similar to the answer provided by Josh Wilson.

这个答案和Josh Wilson给出的答案非常相似。

I went ahead and decided to override the implementation of LengthFieldBasedFrameDecoder as he suggested. I just used fewer lines of code.

我决定按照他的建议重写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);
    }
}

EDIT:

编辑:

I realized that I should post the work that is done in the constructors of the class that is extending the LengthFieldBasedFrameDecoder, so here's the entire class.

我意识到我应该在扩展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);
        }
    }
}

相关文章