---在下方编辑
我实际上正在实现MinaProtocolCodecFilter,以便从串行设备接收消息。
编解码器指定了多个不同的消息(使用它们的pojo),即使实现在99%的情况下都能正常工作,我也会遇到一种类型的消息的问题:只有的消息没有固定长度。我知道最短的长度,但永远不会知道最长的。
这是我收到的异常消息(只是重要部分):
org.apache.mina.filter.codec.ProtocolDecoderException: org.apache.mina.core.buffer.BufferDataException: dataLength: -2143812863 (Hexdump: 02 01 A2 02 01 A0 02)
at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:25
Caused by: org.apache.mina.core.buffer.BufferDataException: dataLength: -2143812863
at org.apache.mina.core.buffer.AbstractIoBuffer.prefixedDataAvailable(AbstractIoBuffer.java:2058)
at my.codec.in.folder.codec.MAFrameDecoder.doDecode(MAFrameDecoder.java:29)
at org.apache.mina.filter.codec.CumulativeProtocolDecoder.decode(CumulativeProtocolDecoder.java:178)
at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:241)
有时dataLength
是阴性的,有时是阳性的(没有发现任何关于这一原因的线索)。
MAFrameDecoder:29是我实现CumulativeProtocolDecoder
的doDecode()
方法(MAX_SIZE=4096)的第二句话:
public boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
throws Exception
{
boolean result=false;
if(in.prefixedDataAvailable(4, MAX_SIZE)) //-->This is line 29
{
int length = in.getInt();
byte[] idAndData = new byte[length];
in.get(idAndData);
//do things, read from buffer, create message, out.write, etc
//if all has been correct, result=true
}
return result;
}
在通过TCP嗅探器调试错误时,我们发现当多条消息插入同一IoBuffer(in)时会引发异常。
似乎我的Decoder
根本无法处理同一缓冲区内的多条消息。但正如我之前所说,还有非固定长度消息问题(我真的不知道它是否有相关性)。在其他doDecode实现中,我看到了另一种管理缓冲区的方法,例如:
while (in.hasRemaining())
或
InputStream is=in.asInputStream();
不管怎样,我尽量避免盲目的脚步,所以这就是我在这里问这个问题的原因。与其只是修复错误,我想知道它的原因。
希望你能帮助我,任何建议都将不胜感激
p.s:通过缓冲区向我发送消息的编码器在false中有其autoExpand参数
2014年11月10日编辑
我一直在探索AbstractIoBuffer方法,发现了这个:
@Override
public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
if (remaining() < prefixLength) {
return false;
}
int dataLength;
switch (prefixLength) {
case 1:
dataLength = getUnsigned(position());
break;
case 2:
dataLength = getUnsignedShort(position());
break;
case 4:
dataLength = getInt(position());
break;
default:
throw new IllegalArgumentException("prefixLength: " + prefixLength);
}
if (dataLength < 0 || dataLength > maxDataLength) {
throw new BufferDataException("dataLength: " + dataLength);
}
return remaining() - prefixLength >= dataLength;
}
我发送的前缀长度是4,所以开关进入最后一个有效的情况:
dataLength = getInt(position());
之后,它抛出具有负dataLength的BufferDataException,这意味着AbstractIoBuffer的position()
方法返回负值。
我一直认为nioBuffer的位置参数永远不会为负值。有什么线索表明为什么会发生这种事吗?
我认为您应该首先读取必须解码的数据包的大小,并确保缓冲区中有足够的字节用于成功完成解码。
如果没有足够的字节,您应该返回false,这样累积协议解码器可以为您获取更多数据。
在返回缓冲区之前,请小心将缓冲区返回到适当的位置,否则将丢失下一次迭代的长度数据。(如果使用4个字节作为长度,则应倒带4个字节)。
编辑:您实际上可以使用IoBuffer的mark()
和reset()
方法来实现这种行为