0

次のコードは a を反復処理しますList<byte[]>()が、問題は、何らかの理由で lengthBuffer が byteData の異なるサイズになることがあることです。

DebugPrintInGame メソッドで、BitConverter.ToInt32()長さを出力してから実際のbyteDataList[i].Length.また。

以下のこのコードでは、データの長さをサーバーに送信するため、サーバーは受信データのサイズと予想される内容を認識してから、実際のデータを送信します。ただし、たとえば、送信された実際のデータよりも長い長さを送信することがありますが、ランダムに発生するため、スレッドの問題である可能性があると思いました-それでも、byteDataListはこの1つのスレッド内でのみ使用されるため、ロックすることさえ無意味ですそれ。私がテストしたところ、送信しているデータは 2kb から 17kb に過ぎません。

私のプロジェクトからのこの小さなスニピットに基づいて、これがなぜ起こっているのか誰にも分かりますか? このコードはすべてクライアント側です。とは同じ長さを与えることが期待されていますが、そうではありません。それが問題だ。BitConverter.ToInt32(lengthBuffer, 0)byteDataList[i].Length

List<byte[]> byteDataList = new List<byte[]>();
//.........

lock (byteDataList) //pointless lock, just used for random testing :\
{
      if (byteDataList.Count > 0)
      {
             for (int i = 0; i < byteDataList.Count; i++)
             {
                 try
                 {
                      byte[] lengthBuffer = BitConverter.GetBytes(byteDataList[i].Length);
                      //quick printout to compare lengths for testing
                      this.QueueOnMainThread(() =>
                      {
                        Tools.DebugPrintInGame("Length buffer " + lengthBuffer.Length + 
                                               +  BitConverter.ToInt32(lengthBuffer,0)+ " "+
                                               + byteDataList[i].Length);  //this should be same as BitConverter lengthBuffer
                      });
                      //send length
                      stream.Write(lengthBuffer, 0, lengthBuffer.Length);
                      //send data
                      stream.Write(byteDataList[i], 0, byteDataList[i].Length);
                      stream.Flush();
                  }
                  catch (Exception ex)
                  {
                       this.QueueOnMainThread(() =>
                       {
                           Tools.DebugPrintInGame("Exception " + ex.ToString());
                       });
                  }
             }

      }
}

サーバーに送信される前に、クライアント側から印刷します。

長さが違うことに気づきましたか?

最後の 2 つが同じはずなのに、長さが異なることに注意してください。いえ

 `lengthBuffer`    = 17672 
 `byteDataList[i]` = 17672 

しかし、時々それは奇妙で不安定になります:

 `lengthBuffer`    = 17672
 `byteDataList[i]` = 2126

lengthBuffer と byteDataList[i] の両方が同じである必要があります。

4

1 に答える 1

1

これは、ループ内の変数のクロージャーに問題がある可能性が最も高いiです (.NET 4.0 以前を使用していると思いますか?) 原因は次のとおりです。

this.QueueOnMainThread(() =>
                      {
                        Tools.DebugPrintInGame("Length buffer " + lengthBuffer.Length + 
                                               +  BitConverter.ToInt32(lengthBuffer,0)+ " "+
                                               + byteDataList[i].Length);  //this should be same as BitConverter lengthBuffer
                      });

上記の変数を参照する方法がわかりますiか? 上記の匿名メソッドは、その変数に対してクロージャーを形成します。つまりi、メソッドが呼び出されるまで評価されません。これは、 の値がilengthBuffer の作成に使用した値でなくなる可能性があることを意味するため、不一致が発生します。

これを修正するには、次のiように、のコピーをループの内部スコープの変数に格納します。

int k = i;
this.QueueOnMainThread(() =>
                          {
                            Tools.DebugPrintInGame("Length buffer " + lengthBuffer.Length + 
                                                   +  BitConverter.ToInt32(lengthBuffer,0)+ " "+
                                                   + byteDataList[k].Length);  //this should be same as BitConverter lengthBuffer
                          });

内側のスコープ変数を閉じることで、意図した値になり、ループが実行されても変化しません。ここでの混乱は、ループ変数が実際には、クロージャーの目的でループ本体の範囲外にあると見なされることです。C# の以降のバージョン (.NET 4.5 用) では、この動作が変更され、ループ変数が内部スコープで閉じられるようになりました。彼らがこの変更を行ったのは、まさにこのような状況でこの問題を簡単に乗り越えてしまうからです。

于 2015-01-14T21:41:01.147 に答える