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