我正在使用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中的这种情况。你能帮我找到合适的方法吗?
答案 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);
}
}
}