![](/img/trans.png)
[英]Can I use DelimiterBasedFrameDecoder and LengthFieldBasedFrameDecoder together in Netty?
[英]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.