マルチスレッド アプリケーションで問題が発生しており、過去 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の瞬間はありませんでした。何が起こっているのか、またはこれをトラブルシューティングするために他に何ができるのか、誰にも何か考えがありますか?
ありがとう、
トム