GetBytes 返回的大小实际上与数据字节不同

GetBytes returning different size than data byte actually is

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

你可以在 DebugPrintInGame 方法中看到我打印了 BitConverter.ToInt32() 长度,然后是实际的 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] 应该相同。

这很可能是循环中 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)中,他们更改了此行为并且循环变量现在在内部范围内关闭。他们之所以做出更改,是因为在这种情况下很容易被这个问题绊倒。