通过NetworkStream发送消息和文件
本文关键字:文件 消息 NetworkStream 通过 | 更新日期: 2023-09-27 18:05:49
我对网络编程很陌生,我对这段代码有几个问题:
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,连接到服务器)
现在我尝试为我的地图编辑器做一个更新,如你所见。首先,我发送一个16字节的消息,其中包含随后将发送的包的数量(Mapeditor.exe文件!),这是为客户端的进度条…
是否有动态的方法来做到这一点?(不是说"读取16字节数组",而是动态地将文本和文件写入流,客户端会自动知道何时读取文本和何时读取文件)
我希望如此,或者有其他方式编写更新/补丁程序吗?游戏开发者如何做到这一点?
谢谢!
PS:有没有办法确保客户端收到所有的包裹,如果有些丢失了,只发送这些并把它们放在一起?
如果您使用TCP,该协议负责排序,重传等。
关于动态发送/接收数据,您可以使用前缀协议,在该协议中,您首先发送一个数字(例如int - 4字节),该数字表示将要发送的消息的长度。然后发送剩下的信息。
接收方等待4字节,然后将其转换为整数并等待该字节数。这个过程会不断重复。
在您的例子中,首先读取16字节,将其解析为字符串,然后将字符串解析为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> msgLengh这样的数量。那件事你也要注意。
无论如何,如果我是你,因为你需要某种进度通知,我会使用流与async BeginRead()。
我只是给了你一个想法,你可以根据自己的意愿进行微调。