“int msgLength = BitConverter.ToInt32(gzBuffer, 0);”处的索引超出范围
我目前正在开发一些用 C# XNA 制作的游戏。 由于我需要通过网络发送大量数据(大约 96kb),因此我使用了一些在互联网上找到的字符串压缩器/解压缩器代码。 代码如下所示:
public static string Compress(string text)
{
byte[] buffer = Encoding.UTF8.GetBytes(text);
MemoryStream ms = new MemoryStream();
using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
{
zip.Write(buffer, 0, buffer.Length);
}
ms.Position = 0;
MemoryStream outStream = new MemoryStream();
byte[] compressed = new byte[ms.Length];
ms.Read(compressed, 0, compressed.Length);
byte[] gzBuffer = new byte[compressed.Length + 4];
System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
return Convert.ToBase64String(gzBuffer);
}
public static string Decompress(string compressedText)
{
byte[] gzBuffer = Convert.FromBase64String(compressedText);
using (MemoryStream ms = new MemoryStream())
{
int msgLength = BitConverter.ToInt32(gzBuffer, 0);
ms.Write(gzBuffer, 4, gzBuffer.Length - 4);
byte[] buffer = new byte[msgLength];
ms.Position = 0;
using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
{
zip.Read(buffer, 0, buffer.Length);
}
return Encoding.UTF8.GetString(buffer);
}
}
它的工作原理如下: - 服务器使用字符串压缩器压缩字符串,然后将其发送到客户端。 - 客户端接收压缩字符串,并将其解压缩以使其可用。
现在奇怪的是,当我单独测试游戏时,代码可以工作,这意味着我在同一台机器上运行服务器和客户端。 当我与我的朋友一起测试(他托管服务器)并且我进行连接时,它也可以工作。 但是,当我托管服务器并且他连接时,它对我的朋友不起作用。 当他连接到我的服务器时,他在“int msgLength = BitConverter.ToInt32(gzBuffer, 0);”处收到“索引超出范围”。 有时他很幸运并进入,但大多数情况下都会失败并返回该错误。 难道服务器没有收到整个字符串发送吗? 我使用 Lidgren gen3 进行网络发送,压缩字符串作为 netMsg.Write(compressedstring); 发送。
有什么想法吗:)? 谢谢!
I am currently working on some game made in C# XNA.
Since I need to send a huge chunk of data over net (bout 96kb), I am using some string compressor/decompressor code, which I found on the internet.
The code looks like this:
public static string Compress(string text)
{
byte[] buffer = Encoding.UTF8.GetBytes(text);
MemoryStream ms = new MemoryStream();
using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
{
zip.Write(buffer, 0, buffer.Length);
}
ms.Position = 0;
MemoryStream outStream = new MemoryStream();
byte[] compressed = new byte[ms.Length];
ms.Read(compressed, 0, compressed.Length);
byte[] gzBuffer = new byte[compressed.Length + 4];
System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
return Convert.ToBase64String(gzBuffer);
}
public static string Decompress(string compressedText)
{
byte[] gzBuffer = Convert.FromBase64String(compressedText);
using (MemoryStream ms = new MemoryStream())
{
int msgLength = BitConverter.ToInt32(gzBuffer, 0);
ms.Write(gzBuffer, 4, gzBuffer.Length - 4);
byte[] buffer = new byte[msgLength];
ms.Position = 0;
using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
{
zip.Read(buffer, 0, buffer.Length);
}
return Encoding.UTF8.GetString(buffer);
}
}
It works like this:
- Server compresses the string using string compressor, where after sending it to the client.
- The client receives the compressed string, and decompress it so it is usable.
Now the weird part is, that the code works when I am testing the game alone, which means I run the server and client on the same machine.
It also works when I am testing with my friend, where he hosts the server, and I connect.
But it ain't working for my friend when I am hosting the server and he connects.
When he connects to my server, he receives "Index out of range" at "int msgLength = BitConverter.ToInt32(gzBuffer, 0);".
Sometimes he is lucky and gets in, but mostly it fails and returns that error.
Can it be that the server ain't getting the whole string sent?
I am using Lidgren gen3 for network sending, and the compressed string is sent as netMsg.Write(compressedstring);
Any ideas :) ?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您在多个地方做出了相同的错误假设:
Stream.Read
将一次性返回您要求的所有数据。你忽略了返回值。不要这样做...诚然,假设有足够的数据,对于MemoryStream
来说应该没问题此外,您可能需要使用MemoryStream.ToArray
方法来转换为字节数组。现在,您还没有显示客户端如何接收字符串 - 您从哪里获取它?
您应该记录服务器发送的字符串和客户端接收的字符串。这绝对是第一步,因此您可以查看数据是否已真正保留。
我怀疑客户端正在尝试解压缩一个空字符串 - 即
Convert.FromBase64
返回一个空字节数组 - 但在您知道正在接收的字符串之前,很难取得任何进展。You're making the same incorrect assumption in multiple places: that
Stream.Read
will return all the data you've asked for in one go. You're ignoring the return value. Don't do that... admittedly it should be okay forMemoryStream
s, assuming there's enough dataAdditionally, you may want to use theMemoryStream.ToArray
method to convert to a byte array.Now, you haven't shown how the client is receiving the string - where are you getting it from?
You should log the string that the server sends, and the string that the client receives. That's the absolute first step, so you can see whether the data has actually been preserved.
I suspect that the client is trying to decompress an empty string - i.e. that
Convert.FromBase64
is returning an empty byte array - but until you know the string that's being received, it's hard to make any progress.