处理Buffer [JAVA-Mina]内的多条消息的异常

时间:2014-11-07 11:59:31

标签: java buffer protocol-buffers apache-mina mina

---编辑下面

我实际上正在实施 Mina ProtocolCodecFilter ,以便从串行设备接收消息。

编解码器指定了多个不同的消息(带有pojos),即使你的实现在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的{​​{1}}方法的第二句话(MAX_SIZE = 4096):

doDecode()

在通过TCP嗅探器调试错误时,我们发现当多个消息插入同一个IoBuffer(in)时,抛出了异常。

似乎我的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; } 根本无法处理同一缓冲区内的多条消息。但正如我之前所说,还有非固定长度的消息问题(我真的不知道它是否有一些相关性)。在其他doDecode实现中,我见过另一种管理缓冲区的方法,例如:

Decoder

while (in.hasRemaining())

无论如何,我正试图避免盲步,所以这就是我在这里问的原因。我想知道它的原因,而不仅仅是修复错误。

希望你能帮助我,任何建议都会非常感激。 :)

p.s:通过缓冲区向我发送消息的编码器在 false 中有 autoExpand 参数。



编辑10/11/2014

我一直在探索AbstractIoBuffer方法并发现了这个:

InputStream is=in.asInputStream();

我发送的prefixLength是4,所以交换机进入最后一个有效的情况:

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

之后,它会抛出具有负数据Length的BufferDataException,这意味着AbstractIoBuffer的dataLength = getInt(position()); 方法返回负值。

我一直认为nioBuffer永远不会对其position参数保持负值。为什么会发生这种情况的任何线索?

1 个答案:

答案 0 :(得分:1)

我认为您应该首先尝试读取必须解码的数据包的大小,并确保缓冲区中剩余足够的字节,以便成功完成解码。

如果没有足够的字节,则应返回false,因此累积协议解码器可以为您获取更多数据。

在返回缓冲区之前,请小心将缓冲区返回到适当的位置,否则将丢失下一次迭代的长度数据。 (如果你使用4个字节作为长度,你应该倒回4个字节)。

编辑:您实际上可以使用IoBuffer的mark()reset()方法来实现此行为