通过TCP发送数据

时间:2012-06-14 09:38:55

标签: c# tcp bytebuffer

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

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

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

我能想到的唯一可能是错误的是我的服务器读入流直到固定缓冲区阵列已满并且因此最终比客户端更多的字节。但是,如果这是问题,我该如何解决这个问题?

我刚刚添加了2个发送方法,因为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());
        }
    }

2 个答案:

答案 0 :(得分:2)

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

但我发现很难相信你的代码实际上就像你描述的那样。这是因为Read()中的GetMovieData()也可能无法填充整个缓冲区。此外,允许StreamReader将一些数据保存在内部缓冲区中,这意味着您可以读取一些完全虚假的数据。

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

答案 1 :(得分:0)

让我试一试试一试,但如果不行则请不要开枪

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

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

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

到此:

nws.Write(buffer, 0, currentBlockSize);