簡體   English   中英

使用 Netty 的 LengthFieldBasedFrameDecoder 時我應該如何處理 ASCII 值?

[英]How should I handle an ASCII value when using Netty's LengthFieldBasedFrameDecoder?

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

我正在開發的軟件可以在沒有 Netty 幫助的情況下與電視通信,所以我在這里以非常規的方式使用 Netty。 我只是使用 Netty 作為解碼器和通道管道來解碼來自各種不同設備的消息。 至少這是我的目標。

我目前正在處理的電視有一個用於 Query Power 的協議命令,電視響應該命令。 響應的第一個字節是長度值。

我的軟件以字節為單位接收該響應,我想使用 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 個字節。

作為一個 hack,我編寫了這段代碼來將消息的第一個字節轉換為 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 中內置的這種情況。 你們能幫我找到正確的方法來處理這個問題嗎?

您可以覆蓋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);
  }
}

這個答案與 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);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM