Skip to content

Instantly share code, notes, and snippets.

@MiguelRipoll23
Last active June 19, 2020 16:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MiguelRipoll23/88fcd83f596bcdda0798a3e4b92d12a5 to your computer and use it in GitHub Desktop.
Save MiguelRipoll23/88fcd83f596bcdda0798a3e4b92d12a5 to your computer and use it in GitHub Desktop.
tcp-packet-parser
// +---------------------------------------------+
// | Packet |
// +---------------------------------------------+
// | id (short) | payload size (short) | payload |
// +------------+----------------------+---------+
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
namespace App
{
public struct Packet
{
public short commandType, payloadSize;
public byte[] payload;
public Packet(short commandType, short payloadSize, byte[] payload)
{
this.commandType = commandType;
this.payloadSize = payloadSize;
this.payload = payload;
}
}
public class Connection
{
public StreamSocket StreamSocket { get; set; }
private readonly IInputStream inputStream = null;
private readonly IOutputStream outputStream = null;
private DataReader dataReader = null;
private DataWriter dataWriter = null;
private CancellationTokenSource cancellationTokenSource = null;
private const uint PacketHeaderSize = 4;
private bool connected = true;
public Connection(StreamSocket streamSocket)
{
StreamSocket = streamSocket;
inputStream = StreamSocket.InputStream;
outputStream = StreamSocket.OutputStream;
dataReader = new DataReader(inputStream)
{
InputStreamOptions = InputStreamOptions.Partial,
ByteOrder = ByteOrder.LittleEndian
};
dataWriter = new DataWriter(outputStream)
{
ByteOrder = ByteOrder.LittleEndian,
UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8
};
cancellationTokenSource = new CancellationTokenSource();
ParsePackets().ContinueWith((task) =>
{
if (task.IsFaulted && task.Exception.GetType() != typeof(TaskCanceledException))
{
Dispose();
}
if (task.IsCompleted)
{
if (connected)
{
connected = false;
}
else
{
Debug.Write("Connection lost.");
}
}
});
}
private void Dispose()
{
if (dataReader != null)
{
dataReader.Dispose();
}
if (dataWriter != null)
{
dataWriter.Dispose();
}
if (StreamSocket != null)
{
StreamSocket.Dispose();
}
}
public void Close()
{
// Cancel read operation
cancellationTokenSource.Cancel();
// Stop loop
connected = false;
// Dispose
Dispose();
}
public async Task ParsePackets()
{
bool headerRead = false;
short command = 0;
short payloadSize = 0;
byte[] payload = null;
while (connected)
{
if (!headerRead)
{
if (dataReader.UnconsumedBufferLength < PacketHeaderSize)
{
await dataReader.LoadAsync(PacketHeaderSize - dataReader.UnconsumedBufferLength).AsTask(cancellationTokenSource.Token);
}
else
{
command = dataReader.ReadInt16();
payloadSize = dataReader.ReadInt16();
headerRead = true;
}
}
else
{
if (payloadSize > 0 && dataReader.UnconsumedBufferLength < payloadSize)
{
await dataReader.LoadAsync((uint)payloadSize - dataReader.UnconsumedBufferLength).AsTask(cancellationTokenSource.Token);
}
else if (payloadSize == 0 || dataReader.UnconsumedBufferLength >= payloadSize)
{
if (payloadSize > 0)
{
payload = new byte[payloadSize];
dataReader.ReadBytes(payload);
}
Packet packet = new Packet(command, payloadSize, payload);
ParsePacket(packet);
headerRead = false;
}
}
}
}
private void ParsePacket(Packet packet)
{
// ...
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment