0

マルチスレッド アプリケーションで問題が発生しており、過去 3 日間デバッグしてきましたが、問題を解決できません。これを書いているのは、これを入力するときに DUH の瞬間があるか、誰かが私が提供するコード スニペットに明らかな何かを見つけてくれることを願ってです。何が起こっているかは次のとおりです。

私は新しい UDP ネットワーク ライブラリに取り組んでおり、UDP データグラムを複数の受信アプリケーションにマルチキャストするデータ プロデューサーを持っています。送信者は、別々の UDP マルチキャスト アドレスと別々のポートにバインドされた 2 つの異なるソケットで送信します。受信側アプリケーションも 2 つのソケットを作成し、それぞれを送信側のマルチキャスト アドレス/ポートの 1 つにバインドします。

レシーバーがデータグラムを受信すると、それを MemoryStream のバッファーからコピーし、それをスレッド セーフ キューに入れます。別のスレッドがそれを読み取り、MemoryStream からデータをデコードします。

どちらのソケットにも独自のキューがあります。

今起こっていることは本当に奇妙です。それはランダムに発生し、再現性がなく、複数の受信アプリケーションを実行すると、時々ランダムに発生するのはそのうちの 1 つだけです。

基本的に、MemoryStream をキューから読み取るスレッドは、ReadInt32() などの BinaryReader を介して読み取り、それによってデータをデコードします。ただし、時々、データを読み取るときに、読み取ったデータが正しくありません。たとえば、送信者が決してエンコードしない負の整数です。

ただし、前述のように、受信アプリケーションの 1 つでのみデコードが失敗し、他のアプリケーションではデータグラムが正常にデコードされます。おそらくUDPデータグラムにバイト破損か何かがあると言うかもしれませんが、入ってくるすべてのデータグラムをログに記録し、すべての受信者でそれらを比較したところ、すべてのアプリケーションが受信したデータグラムは完全に同一です. デコードに失敗したデータグラムをディスクにダンプし、それを読み取ってデコーダーを実行する単体テストを作成すると、問題なくデコードされます。また、デコーダーの周りに try/catch をラップし、キャッチ内の MemoryStream の位置をリセットして、デコーダーを再度実行すると、正常にデコードされます。さらに奇妙なことに、これは両方のソケットをバインドして送信者からデータを読み取るときにのみ発生します。

何が起こっているのかに対応するコードを次に示します。

これは、ソケットの受信コールバックです。

        private void ReceiveCompleted(object sender, SocketAsyncEventArgs args)
    {
        if (args.SocketError != SocketError.Success)
        {
            InternalShutdown(args.SocketError);
            return;
        }

        if (args.BytesTransferred > SequencedUnitHeader.UNIT_HEADER_SIZE)
        {
            DataChunk chunk = new DataChunk(args.BytesTransferred);
            Buffer.BlockCopy(args.Buffer, 0, chunk.Buffer, 0, args.BytesTransferred);

            chunk.MemoryStream = new MemoryStream(chunk.Buffer);
            chunk.BinaryReader = new BinaryReader(chunk.MemoryStream);

            chunk.SequencedUnitHeader.SequenceID = chunk.BinaryReader.ReadUInt32();
            chunk.SequencedUnitHeader.Count = chunk.BinaryReader.ReadByte();

            if (prevSequenceID + 1 != chunk.SequencedUnitHeader.SequenceID)
            {
                log.Error("UdpDatagramGap\tName:{0}\tExpected:{1}\tReceived:{2}", unitName, prevSequenceID + 1, chunk.SequencedUnitHeader.SequenceID);
            }
            else if (chunk.SequencedUnitHeader.SequenceID < prevSequenceID)
            {
                log.Error("UdpOutOfSequence\tName:{0}\tExpected:{1}\tReceived:{2}", unitName, prevSequenceID + 1, chunk.SequencedUnitHeader.SequenceID);
            }

            prevSequenceID = chunk.SequencedUnitHeader.SequenceID;

            messagePump.Produce(chunk);
        }
        else
            UdpStatistics.FramesRxDiscarded++;

        Socket.InvokeAsyncMethod(Socket.ReceiveAsync, ReceiveCompleted, asyncReceiveArgs);
    }

データをデコードするスタブ コードを次に示します。

        public static void OnDataChunk(DataChunk dataChunk)
    {
        try
        {
            for (int i = 0; i < dataChunk.SequencedUnitHeader.Count; i++)
            {
                int val = dataChunk.BinaryReader.ReadInt32();

                if(val < 0)
                    throw new Exception("EncodingException");

                // do something with that value
            }
        }
        catch (Exception ex)
        {
            writer.WriteLine("ID:" + dataChunk.SequencedUnitHeader.SequenceID + " Count:" + dataChunk.SequencedUnitHeader.Count + " " + BitConverter.ToString(dataChunk.Buffer, 0, dataChunk.Size));
            writer.Flush();
            log.ErrorException("OnDataChunk", ex);

            log.Info("RETRY FRAME:{0} Data:{1}", dataChunk.SequencedUnitHeader.SequenceID, BitConverter.ToString(dataChunk.Buffer, 0, dataChunk.Size));
            dataChunk.MemoryStream.Position = 0;

            dataChunk.SequencedUnitHeader.SequenceID = dataChunk.BinaryReader.ReadUInt32();
            dataChunk.SequencedUnitHeader.Count = dataChunk.BinaryReader.ReadByte();

            OnDataChunk(dataChunk);
        }
    }

catch{} の部分で、MemoryStream.Position を 0 にリセットして同じメソッドを再度呼び出すだけで、次回は問題なく動作することがわかりますか? この時点で私は本当にアイデアがありません。残念ながら、これを書いているDUHの瞬間はありませんでした。何が起こっているのか、またはこれをトラブルシューティングするために他に何ができるのか、誰にも何か考えがありますか?

ありがとう、

トム

4

1 に答える 1

0

複数スレッドによる非同期アクセスにより、データ破損が発生しているようです。datachunk メンバーがスレッドセーフな方法でアクセスされていることを確認できますか?

于 2010-06-15T10:21:15.313 に答える