通过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:有没有办法确保客户端收到所有的包裹,如果有些丢失了,只发送这些并把它们放在一起?

通过NetworkStream发送消息和文件

如果您使用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()。

我只是给了你一个想法,你可以根据自己的意愿进行微调。