I’ve written an application which listens to a port and receives some packets,according to my customized protocol, the packets are either 49 byte to 1500 byte, which i can tell from data length in the packet. the way i should interpret and deal with data in 49 byte packets and bigger packets are different.
The problem is that when i receive packets less than 1374 byte everything is ok, but when the packet length gets more, i receive the following exception and i also lose 4 last bytes of my data(i’ve tested with a 1384byte packet and i lost the last 4 bytes)
Exception which is raised:
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: startIndex
each 49 byte packet has 35 byte of data, and the data length of bigger packets are non-deterministic(because of compression).
i found out sometimes the last 4 bytes are in a seperate “bytes” and “result” variables,meaning they are being treated like new packets and are not being attached to the packet they belong to.
here’s the code for receiving data:
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);
}
According to Greg Suggestion and my researches,i also tried using following method:
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);
}
}
When using TCP, you must keep in mind that the size of the data blocks you put in is not guaranteed to be the same size of data blocks you get out on the receiving side. TCP is a stream protocol, so it guarantees that the same bytes get to the other side in the same order as they were sent (if not, the socket connection will be reset). TCP does not maintain any kind of block boundaries between calls to
send(), and blocks may be arbitrarily split or coalesced depending on network conditions.Your receiver must be prepared to handle receiving any amount of data from the calls to
stream.Read(), but your code does not appear to do this. For example, correctly written receiver code should continue to work correctly even ifstream.Read()receives only one byte at a time.