2012-06-14 233 views
0

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

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

但是当我尝试播放电影时,它无法播放,如果我查看每个电影(客户端和服务器)的文件长度,则服务器电影比客户端电影更大,当我查看命令时屏幕在发送/接收数据的末尾有多于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

是有原因的,为什么Read()返回读取的字节数,它可能会比缓冲区的大小返回较少。正因为如此,你应该在SendData()做类似nws.Write(buffer, 0, currentBlockSize);。但是这会破坏你的协议,因为这些块不会再有大小了。

但是我发现很难相信你的代码实际上表现了你描述的方式。那是因为Read()GetMovieData()也可能不会填满整个缓冲区。另外,允许StreamReader将一些数据保留在内部缓冲区中,这意味着您可以读取一些完全虚假的数据。

我认为这样的代码,在那里你合并Stream s和StreamReader s/StreamWriter s是一个非常糟糕的主意。这将是很难使其实际上是正确的。你应该做的是使你的协议完全基于字节(不是基于字符),即使这些字节是ASCII编码的"SEND"

0

让我给它试试,但如果它不起作用,不要拍我

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

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

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

这样:

nws.Write(buffer, 0, currentBlockSize); 
+0

,缓冲区中剩余的字节不会是零,他们将以前的内容缓冲区。 – svick