2015-11-02 44 views
1

我正在使用Network Stream, TcpListener and Sockets如何確保流完全讀取?

我想確保來自發件人的所有數據都被接收者接收。

我有下面的代碼接收機

private void StartReciever() 
{ 
    util.LoadSettings(); 

    string tcpIpAddress = util.svrSettings["IpAddress"]; 
    string port = util.svrSettings["Port"]; 
    string outDir = util.svrSettings["isOutput"]; 

    new Thread(
    () => 
    { 
     if (!File.Exists(util.settingFile)) 
      Logger("Please setup the services first."); 
     else 
     { 
      try 
      { 
       IPAddress ipAddress = IPAddress.Parse(tcpIpAddress); 
       TcpListener tcpListener = new TcpListener(ipAddress, Convert.ToInt32(port)); 

       tcpListener.Start(); 

       Logger("\nWaiting for a client to connect..."); 

       //blocks until a client connects 
       Socket socketForClient = tcpListener.AcceptSocket(); 

       Logger("\nClient connected"); 

       //Read data sent from client 
       NetworkStream networkStream = new NetworkStream(socketForClient); 
       int bytesReceived, totalReceived = 0; 

       string fileName = "testing.txt"; 

       byte[] receivedData = new byte[10000]; 
       do 
       { 
        bytesReceived = networkStream.Read 
         (receivedData, 0, receivedData.Length); 
        totalReceived += bytesReceived; 
        Logger("Progress of bytes recieved: " + totalReceived.ToString()); 
        if (!File.Exists(fileName)) 
        { 
         using (File.Create(fileName)) { }; 
        } 

        using (var stream = new FileStream(fileName, FileMode.Append)) 
        { 
         stream.Write(receivedData, 0, bytesReceived); 
        } 

       } 
       while (bytesReceived != 0); 
       Logger("Total bytes read: " + totalReceived.ToString()); 

       socketForClient.Close(); 
       Logger("Client disconnected..."); 

       tcpListener.Stop(); 
      } 
      catch (Exception ex) 
      { 
       // Error : "Only one usage of each socket address (protocol/network address/port) is normally permitted"  
       Logger("There is some error: " + ex.Message); 
      } 
     } 
    }).Start(); 
} 

我怎樣才能確保後do-while環路我的代碼執行?

發件人代碼:

private static void SendData(string tcpIpAddress, string port, string filename) 
{ 
    new Thread(
    () => 
     { 
      TcpClient tcpClient = new TcpClient(tcpIpAddress, Convert.ToInt32(port)); 
      //const int bufsize = 8192; 
      const int bufsize = 10000; 
      var buffer = new byte[bufsize]; 
      NetworkStream networkStream = tcpClient.GetStream(); 

      using (var readFile = File.OpenRead(filename)) 
      { 
       int actuallyRead; 
       while ((actuallyRead = readFile.Read(buffer, 0, bufsize)) > 0) 
       { 
        networkStream.Write(buffer, 0, actuallyRead); 
       } 
      } 
     }).Start(); 
} 
+0

您應該考慮使用'Task'而不是始終創建新的線程。除非你絕對不能使用'Task'。 – Bauss

+0

終止一個tcp消息,您需要使用以下方法之一(或多個方法)。 1)Ascii:添加終止字符,如'\ n。 2)ASCII或二進制:在消息的開頭添加一個字節計數。 3)Asii或Binary:使用固定長度的消息,其中每個消息(或消息類型)具有相同的長度。 – jdweng

回答

3

我怎樣才能確保我的代碼後執行循環執行?

在這裏,這很容易,因爲您可以關閉發送方的連接,這將導致接收方讀取零字節並終止循環。

其實你忘了清理髮件人。處置所有資源。這解決了這個問題。

您的代碼將受益於Code Review SE。我看到大約十幾個對這個問題無關緊要的問題。這對你來說是一個改善自我的好方法。

例如,您可以用Stream.Copy替換複製循環。

+0

非常感謝....救生員:) :) – Gaurav123

+0

我有一個查詢。正如你所提到的,我可以使用''Stream.Copy''代替循環。你可以請參考一些例子或樣本,以便我可以更好地理解它,因爲我正在第一次使用流式傳輸。 – Gaurav123

+0

該方法非常易於使用。任何具體問題?將一個流複製到另一個流,並在源空時停止。 – usr

0

我已經看到這種情況預先設置數據的常用方法與將要發送的字節數被髮送。這樣接收器就知道數據包已被讀取。即使網絡中斷或發送者不中斷地發送其他內容。

請注意,這樣做,你也可以閱讀前8個字節(或4,如果一個Int32將做的工作)分配讀取緩衝區,它可以幫助優化緩衝區大小

這樣做是另一種常見的方法之前,與一個特定的終止符,但那麼你必須保證,無論你發送不能包含該終結者