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

标签 java buffer protocol-buffers apache-mina mina

---编辑如下

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

编解码器指定了多个不同的消息(及其 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 是我实现 CumulativeProtocolDecoderdoDecode() 方法 (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:通过缓冲区向我发送消息的编码器的 autoExpand 参数为 false

<小时/> <小时/>

编辑 2014 年 10 月 11 日

我一直在探索 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;
}

我发送的 prefixLength 是 4,因此交换机在最后一个有效情况下输入:

dataLength = getInt(position());

之后,它抛出带有负 dataLength 的 BufferDataException,这意味着 AbstractIoBuffer 的 position() 方法返回负值。

我一直认为 nioBuffer 的位置参数永远不能保持负值。有任何线索说明为什么会发生这种情况吗?

最佳答案

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

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

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

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

关于java - 处理 Buffer 内多条消息的异常 [JAVA-Mina],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26800801/

相关文章:

buffer - SignalR 消息计数性能计数器

python gevent websocket 客户端收到错误 "DecodeError: Truncated message"回显 Protocol Buffer 消息

java - protobuf-net 序列化/反序列化 DateTime 和 Guid 类型

java - Apache NiFi : FlowFileHandlingException when transfer FlowFile in custom processor

java - 为什么 hadoop fs 命令无法执行来创建目录?

java - 在我的测试中如何从 Spring Cloud Stream 获取 channel 对象

Elasticsearch 丢弃了太多请求——缓冲区会改善情况吗?

java - 在 DispatcherServlet 中未找到名称为 'HelloWeb' 的 URI [/HelloWeb/] 的 HTTP 请求的映射

c++ - 如何将缓冲区中的字符串添加到另一个数组并打印出来?

java - 协议(protocol)-jar-maven-插件 : Not generating grpc service stubs