0

下面的代码遍历 aList<byte[]>()但是问题是由于某种原因,有时 lengthBuffer 是 byteData 的不同大小。

您可以在 DebugPrintInGame 方法中看到,我打印了BitConverter.ToInt32()length 和 actual byteDataList[i].Length,这两个数字应该完全相同,而且很多时候它们是一样的,但是由于很多时候我不知道的原因,现在它们不是任何一个。

使用下面的代码,它将数据的长度发送到服务器,以便服务器知道传入数据的大小和预期的内容,然后发送实际数据。然而,有时它会发送比实际发送的数据更大的长度,但它是随机发生的,这让我相信这可能是一个线程问题——尽管如此 byteDataList 只在这个线程中使用,所以它甚至对我来说毫无意义锁定它。在我的测试中,我发送的数据不超过 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());
                       });
                  }
             }

      }
}

在发送到服务器之前从客户端打印出来:

注意不同的长度?

当最后两个应该相同时,请注意不同的长度。IE

 `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在调用该方法之前不会对其进行评估。这意味着 的值i可能不再是您用于创建 lengthBuffer 的值,因此您会得到不匹配的结果。

要解决此问题,请将 的副本存储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 回答