2012-06-14 280 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