--- РЕДАКТИРОВАТЬ ниже
На самом деле я реализую 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 — это второе предложение моей реализации метода doDecode()
CumulativeProtocolDecoder
(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())
or
InputStream is=in.asInputStream();
В любом случае, я пытаюсь избежать слепых шагов, поэтому я спрашиваю об этом здесь. Вместо того, чтобы просто исправить ошибку, я хотел бы знать ее причину.
Надеюсь, вы можете мне помочь, любой совет будет очень признателен. :)
ps: кодировщик, который отправляет мне сообщения через буфер, имеет параметр autoExpand в false.
ИЗМЕНИТЬ 11.10.2014
Я изучал метод 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());
После этого создается исключение BufferDataException с отрицательной длиной данных, что означает, что метод position()
класса AbstractIoBuffer возвращает отрицательное значение.
Я всегда думал, что nioBuffer никогда не может содержать отрицательное значение параметра position. Любые подсказки, почему это происходит?