2012-10-14 74 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字节的数据。 –

相关问题