1

---以下を編集

シリアル デバイスからメッセージを受信するために、実際にMina ProtocolCodecFilterを実装しています。

コーデックは複数の異なるメッセージ (pojos を含む) を指定し、実装が 99% の確率で正しく動作する場合でも、1 つのタイプのメッセージで問題が発生します:固定長を持たない唯一のメッセージです。最小の長さはわかりますが、最大の長さはわかりません。

これは私が受け取った例外メッセージです (重要な部分のみ):

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)の実装の 2 番目の文です。

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();

とにかく、私は盲目的なステップを避けようとしているので、ここで質問しています. エラーを修正するだけでなく、その理由を知りたいです。

アドバイスをいただければ幸いです。: )

ps: バッファーを介してメッセージを送信するエンコーダーのautoExpandパラメーターはfalseです。



編集 10/11/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());

その後、負の dataLength で BufferDataException をスローします。これは、AbstractIoBuffer のposition()メソッドが負の値を返していることを意味します。

私は常に、nioBuffer がその位置パラメーターに負の値を保持することはできないと考えていました。なぜこれが起こっているのかの手がかりはありますか?

4

1 に答える 1

2

最初にデコードする必要があるパケットのサイズを読み取って、デコードが正常に完了するのに十分なバイトがバッファに残っていることを確認する必要があると思います。

十分なバイトがない場合は、false を返す必要があります。これにより、累積プロトコル デコーダーがより多くのデータを取得できるようになります。

バッファーを返す前に、バッファーを適切な位置に戻すように注意してください。そうしないと、次の反復で長さデータが失われます。(長さに 4 バイトを使用している場合は、4 バイトを巻き戻す必要があります)。

編集:実際にIoBufferのmark()andメソッドを使用して、この動作を実現できますreset()

于 2014-11-11T14:48:49.670 に答える