I'm implementing a TCP client to read data from a sensor. The sensor sends messages to connected clients framed with a start sequence, messages, checksum and end sum bytes. Because the sensor is installed at a remote location, I'm currently reading previously captured network data from a pcap dump into a MemoryStream. The TCP data is simulated from a capture file using bittwist (not real-time client-server communication).
Please advise on how to improve the method below that reads TCP messages including framing bytes, through a MemoryStream since I can't use NetworkStream? Is my checksum calculation correct? The sensor documentation indicates that to calculate it you must include all payload data except starting and ending sequence.
I have two while loops, one to first check start sequence (frame start), once done.
The second loop checks for the checksum value, end sequence (frame end) and if not, treats this as a message payload and reads from the stream until a valid end sequence (frame end) is found. Each (n) payload starts with a 3 bytes header (2 bytes identifier + 1 byte length of the succeeding data) and then the actual data.
private static void Decode(MemoryStream memoryStream)
{
var frameStartSequenceBuffer = new byte[] { 0xCA, 0xCB, 0xCC, 0xCD };
var frameChecksumBuffer = new byte[1];
var frameEndSequenceBuffer = new byte[] { 0xEA, 0xEB, 0xEC, 0xED };
var startSequenceBuffer = new byte[4];
var endSequenceBuffer = new byte[4];
var messages = new List<byte[]>();
var read = 0;
while (read < startSequenceBuffer.Length)
{
read += memoryStream.Read(startSequenceBuffer, 0, startSequenceBuffer.Length);
if (Helpers.ByteArrayCompare(startSequenceBuffer, frameStartSequenceBuffer))
break;
}
while (memoryStream.Capacity > read)
{
read += memoryStream.Read(frameChecksumBuffer, 0, frameChecksumBuffer.Length);
read += memoryStream.Read(endSequenceBuffer, 0, endSequenceBuffer.Length);
if (Helpers.ByteArrayCompare(endSequenceBuffer, frameEndSequenceBuffer))
break;
var readPayload = frameChecksumBuffer.Concat(endSequenceBuffer).ToArray();
var messageBuffer = new byte[3 + endSequenceBuffer[1]];
readPayload.CopyTo(messageBuffer, 0);
read += memoryStream.Read(messageBuffer, readPayload.Length, messageBuffer.Length - readPayload.Length);
messages.Add(messageBuffer);
}
var calculatedChecksum = Helpers.CalculateChecksumBitwise(messages.SelectMany(o => o).Concat(frameChecksumBuffer).ToArray());
if (calculatedChecksum != frameChecksumBuffer[0])
{
Console.WriteLine("Messages: {0} - Corrupt", messages.Count);
return;
}
Console.WriteLine("Messages: {0} - Valid", messages.Count);
}
Each TCP packet from the sensor encapsulates an array of (n) messages delimited with a 3 bytes headers.
The checksum is calculated from all data without the start sequence and the end sequence. The Checksum is a simple XOR Assignment of all n data bytes. Below is the checksum calculation method that I've implemented.
public static byte CalculateChecksumBitwise(IList<byte> byteToCalculate)
{
var checksum = 0;
for (var i = 0; i < byteToCalculate.Count - 1; i++)
{
checksum = checksum ^ byteToCalculate[i];
}
return (byte)checksum;
}
dataStream
isn't aSystem.IO.Stream
we'll need the implementation ofdataStream.Read
too: without more context it's not clear whether or not the way it's being called is introducing a lot of bugs. \$\endgroup\$