以下代码遍历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());
});
}
}
}
}
在客户端打印之前,甚至将其发送到服务器:
当最后两个应该相同时,请注意不同的长度。 即
`lengthBuffer` = 17672
`byteDataList[i]` = 17672
但有时会变得怪异而且不稳定:
`lengthBuffer` = 17672
`byteDataList[i]` = 2126
lengthBuffer和byteDataList [i]都应该是相同的。
答案 0 :(得分: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)中,他们更改了此行为,现在使用内部作用域关闭循环变量。他们做出了改变,因为在这种情况下,很容易绊倒这个问题。