0

我有一个客户端服务器情况,客户端将数据(例如电影)发送到服务器,服务器将该数据保存到 HDD。

它通过固定的字节数组发送数据。发送完字节后,服务器会询问是否还有更多,如果有,则发送更多等等。一切进展顺利,所有数据都得到了传递。

但是当我尝试播放电影时,它无法播放,如果我查看每部电影(客户端和服务器)的文件长度,则服务器电影大于客户端电影。当我查看最后的命令屏幕时在发送/接收数据中,跨越的字节数超过 100%。

我唯一能想到的可能是错误的事实是,我的服务器在流中读取直到固定缓冲区数组已满,因此最后的字节数比客户端多。但是,如果这是问题,我该如何解决?

我刚刚添加了两种发送方法,因为 tcp 连接有效,欢迎任何帮助。

客户

public void SendData(NetworkStream nws, StreamReader sr, StreamWriter sw)
{
    using (FileStream reader = new FileStream(this.path, FileMode.Open, FileAccess.Read))
    {                
         byte[] buffer = new byte[1024];
         int currentBlockSize = 0;

         while ((currentBlockSize = reader.Read(buffer, 0, buffer.Length)) > 0)
         {
             sw.WriteLine(true.ToString());
             sw.Flush();
             string wait = sr.ReadLine();
             nws.Write(buffer, 0, buffer.Length);
             nws.Flush();
             label1.Text = sr.ReadLine();
         }
         sw.WriteLine(false.ToString());
         sw.Flush();                
    }
}

服务器

    private void GetMovieData(NetworkStream nws, StreamReader sr, StreamWriter sw, Film filmInfo)
    {
        Console.WriteLine("Adding Movie: {0}", filmInfo.Titel);
        double persentage = 0;

        string thePath = this.Path + @"\films\" + filmInfo.Titel + @"\";
        Directory.CreateDirectory(thePath);

        thePath += filmInfo.Titel + filmInfo.Extentie;

        try
        {
            byte[] buffer = new byte[1024]; //1Kb buffer

            long fileLength = filmInfo.TotalBytes;
            long totalBytes = 0;

            using (FileStream writer = new FileStream(thePath, FileMode.CreateNew, FileAccess.Write))
            {
                int currentBlockSize = 0;
                bool more;
                sw.WriteLine("DATA");
                sw.Flush();
                more = Convert.ToBoolean(sr.ReadLine());


                while (more)
                {
                    sw.WriteLine("SEND");
                    sw.Flush();
                    currentBlockSize = nws.Read(buffer, 0, buffer.Length);
                    totalBytes += currentBlockSize;
                    writer.Write(buffer, 0, currentBlockSize);

                    persentage = (double)totalBytes * 100.0 / fileLength;
                    Console.WriteLine(persentage.ToString());

                    sw.WriteLine("MORE");
                    sw.Flush();
                    string test = sr.ReadLine();
                    more = Convert.ToBoolean(test);                       
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
4

2 回答 2

2

返回读取的字节数是有原因Read()的:它可能会返回小于缓冲区的大小。因此,您应该执行类似nws.Write(buffer, 0, currentBlockSize);in 的操作SendData()。但这会破坏您的协议,因为这些块将不再具有大小。

但我发现很难相信您的代码实际上会按照您描述的方式运行。那是因为Read()inGetMovieData()也可能不会填满整个缓冲区。此外,StreamReader允许将一些数据保存在内部缓冲区中,这意味着您可以读取一些完全伪造的数据。

我认为像这样的代码,你将Streams 和StreamReaders/ StreamWriters 结合起来是一个非常糟糕的主意。很难让它真正正确。相反,您应该做的是使您的协议完全基于字节(而不是基于字符),即使这些字节是 ASCII 编码的"SEND"

于 2012-06-14T09:54:12.070 回答
0

让我试一试,但如果它不起作用,请不要向我开枪

我看到您的缓冲区大小为 1024,无论您发送的文件中还剩下多少字节。假设您有一个 2900 字节的文件,需要发送 3 次,最后一次发送将只剩下 852 字节要发送。然而,您创建了一个 1024 的缓冲区并发送了超过 1024 个字节。这意味着您的服务器接收到 852 个字节的真实数据和 172 个零填充字节。尽管如此,所有这 172 个字节都保存到服务器上的电影文件中。

我想有一个简单的解决方法:当您将数据写入服务器时,使用currentBlockSizeas 参数作为长度。因此,SendData在客户端的方法中,在 while 循环内,更改:

nws.Write(buffer, 0, buffer.Length);

对此:

nws.Write(buffer, 0, currentBlockSize);
于 2012-06-14T09:56:31.130 回答