我对网络编程很陌生,我对这段代码有几个问题:
if (client.Connected)
{
ChangeLabel("Mit dem Server verbunden...");
NetworkStream stream = client.GetStream();
FileStream fs = null;
try
{
fs = new FileStream("Mapeditor2.exe", FileMode.Create);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
Environment.Exit(0);
}
byte[] bResponse = new byte[16];
stream.Read(bResponse, 0, 16);
string sResponse = System.Text.Encoding.UTF8.GetString(bResponse);
int NoOfPackets = Convert.ToInt32(sResponse);
float progress = 0;
float progressPercent = 100.0f / (float)NoOfPackets;
byte[] buffer = new byte[128];
int bytesRead;
for (int i = 0; i < NoOfPackets; i++)
{
bytesRead = stream.Read(buffer, 0, 128);
fs.Write(buffer, 0, bytesRead);
progress += progressPercent;
ChangeProgress((int)progress);
}
fs.Close();
stream.Close();
}
(客户端是TcpClient,与服务器的连接)
现在我尝试为我的mapeditor制作更新程序,如您所见。 首先,我发送一个16字节的消息,其中包含之后将发送的包的数量(Mapeditor.exe文件!),这是用于客户端的进度条...
有没有动态的方法来做到这一点? (不是说“读取16字节数组”并将文本和文件动态写入流中,客户端自动知道何时必须阅读文本和文件)
我希望如此,还是有其他方式来编写更新程序/修补程序?游戏开发者如何做到这一点?
谢谢!
PS:有没有办法确保客户端收到所有包裹,如果有人丢失了,只发送这些包裹并将它们放在一起?
答案 0 :(得分:2)
如果您使用TCP,协议将负责订购,重新传输等。
关于动态发送/接收数据,您可以使用前缀协议,在该协议中首先发送一个数字(比如一个int - 4字节),表示要发送的消息的长度。之后,您发送剩余的消息。
接收器等待4个字节,然后将它们转换为整数并等待该字节数。这个过程一次又一次地重复。
在您的情况下,首先读取16个字节,将其解析为字符串,然后将字符串解析为int是没有意义的。您的发件人可以立即将int转换为字节,如下所示:
// lengthBytes.Length = 4 bytes, which is sizeof(int)
byte[] lengthBytes = BitConverter.GetBytes(anInt);
然后将其发送到电线上。
然后,在接收端,在您的代码中,您确实喜欢:
byte[] msgLengthBytes = new byte[sizeof(int)]; // or hardcode 4 here, I'm a generalization junkie
stream.Read(msgLengthBytes, 0, msgLengthBytes.Length);
int msgLength = BitConverter.GetInt32(msgLengthBytes, 0);
此外,假设您每次从流中读取时都会读取您期望的字节数,而不是假设您应该使用以下内容:
int transfered = 0;
while (transfered < msgLength)
{
bytesRead = stream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, bytesRead);
transfered += bytesRead;
progress += (bytesRead / msgLength) * 100;
ChangeProgress(progress); // You can't use int here anymore, use Math to round or something, for your progress bar
}
另外,在我的代码片段中,您可能会读取最后一个接收操作,例如:transfered + bytesRead&gt; msgLengh,如果你在流上连续发送数据。你也必须照顾好。
无论如何,如果我是你,并且因为你需要某种进度通知器,我会使用带有异步BeginRead()的流。
我刚给你一个想法,你可以随意微调它。