2012-10-14 109 views
0

我已經編寫了一個應用程序,用於偵聽端口並接收一些數據包,根據我的定製協議,數據包爲49字節到1500字節,我可以從數據長度數據包。我應該解釋和處理49字節數據包和更大數據包的方式是不同的。從TCP客戶端接收數據時出錯

問題是,當我收到小於1374字節的數據包時,一切正常,但是當數據包長度變得更大時,我收到以下異常,並且我還丟失了4個數據的最後一個字節(我用1384byte數據包,我丟失了最後4個字節)

引發的異常: 索引超出範圍。必須是非負數且小於集合的大小。 參數名稱:startIndex

每個49字節的數據包有35個字節的數據,並且較大數據包的數據長度是非確定性的(由於壓縮)。

我發現有時最後4個字節是在一個單獨的「字節」和「結果」變量中,這意味着它們被當作新數據包來處理,並且不會被附加到它們所屬的數據包上。

這裏是用於接收數據的代碼:

TcpClient Client = obj as TcpClient; 
     EndPoint ep = Client.Client.RemoteEndPoint; 
     List<Byte> result = new List<byte>(); 
     result.Capacity = 2000; 
     try 
     { 


      NetworkStream stream = Client.GetStream(); 
      int i = 49; 
      while ((i = stream.Read(bytes, 0,49)) != 0) 
      { 

       for (int id = 0; id < i; id++) 
       { 
        result.Add(bytes[id]); 
       } 
//reading data length to determine packet length 
       byte[] tmp = new byte[2]; 
       tmp = BitConverter.GetBytes(BitConverter.ToUInt16(result.ToArray(), 9)); 
       if (BitConverter.IsLittleEndian) 
       { 
        Array.Reverse(tmp); 
       } 
       Int16 l = BitConverter.ToInt16(tmp, 0); 
       if (l>35) 
       { 
        stream.Read(bytes, result.Count, l - 35); 
        for (int id = 49; id <((l-35)+49); id++) 
        { 
         result.Add(bytes[id]); 
        } 
        if (this.TCPDataReceivedHandler != null) 
        { 
         this.TCPDataReceivedHandler(ep, result.Count, result.ToArray()); 
         result.Clear(); 
         Array.Clear(bytes, 0, 2000); 
         result.Capacity = 2000; 
        } 
       } 
       else 
       { 
        if (this.TCPDataReceivedHandler != null) 
        { 
         this.TCPDataReceivedHandler(ep, result.Count, result.ToArray()); 
         result.Clear(); 
         Array.Clear(bytes, 0, 2000); 
         result.Capacity = 2000; 
        } 
       } 


      } 
      System.Diagnostics.Debug.WriteLine("client Close"); 
      Client.Close(); 

     } 
     catch (System.Exception ex) 
     { 
      throw ex; 
     } 
     finally 
     { 
      Client.Close(); 
      this.clients.Remove(Client); 
     } 

據格雷格建議和我的研究,我還用以下方法嘗試:

NetworkStream stream = Client.GetStream(); 
      int bytesread = 0, OffsetTemp = 0; 

      while (stream.CanRead) 
      { 
       OffsetTemp = 0; 

       bytesread += stream.Read(bytess, OffsetTemp, 11); 
       OffsetTemp = OffsetTemp + 11; 



       byte[] tmp = new byte[2]; 
       tmp = BitConverter.GetBytes(BitConverter.ToUInt16(bytess.ToArray(), 9)); 
       if (BitConverter.IsLittleEndian) 
       { 
        Array.Reverse(tmp); 
       } 
       Int16 l = BitConverter.ToInt16(tmp, 0); 

       bytesread += stream.Read(bytess, OffsetTemp++, 11 + l + 3); 
       for (int id = 0; id < l + 14; id++) 
       { 
        result.Add(bytess[id]); 
       } 

       if (this.TCPDataReceivedHandler != null) 
       { 
        this.TCPDataReceivedHandler(ep, result.Count, result.ToArray()); 
        result.Clear(); 
        Array.Clear(bytess, 0, 2000); 
       } 

      } 

回答

0

使用TCP時,你必須記住,您輸入的數據塊的大小爲不保證與您在接收端獲得的數據塊的大小相同。 TCP是一個流協議,所以它保證相同的字節按照它們發送的順序到達另一端(如果沒有,套接字連接將被重置)。 TCP不會在對send()的調用之間維護任何類型的塊邊界,並且可能會根據網絡條件對塊進行任意分割或合併。

您的接收器必須準備好接收來自stream.Read()調用的任何數量的數據,但您的代碼似乎沒有這樣做。例如,即使stream.Read()一次只接收一個字節,正確書寫的接收器代碼仍應繼續正常工作。

+0

感謝格雷格,但我怎麼能確信,數據包不會互相混淆,如果我繼續從stream.Read()讀取而不注意數據包中的數據長度字段?數據包以短時間連續發送。 –

+0

它看起來像你的協議有一個標題,指定下面的數據塊的長度。所以對於當前塊只讀很多,然後循環到頂部並讀取下一個塊的長度標題。 –

+0

親愛的格雷格,我試着用你的建議,但沒有工作,我仍然有問題接收超過1380字節的數據。 –

相關問題