internal void SendPartialPacket(PartialPacket p) { byte[] type = { (byte)p.Type }; byte[] hasId = { p.HasId ? (byte)1 : (byte)0 }; byte[] isbuffered = { 1 }; byte[] length = BitConverter.GetBytes(p.Data.Length); byte[] posBytes = BitConverter.GetBytes(p.Position); byte[] isEndBytes = p.IsEnd ? new byte[] { 1 } : new byte[] { 0 }; byte[] totalLengthBytes = BitConverter.GetBytes(p.TotalDataSize); byte[] arrData = p.Data; byte[] b; if (p.HasId) { b = ByteArrayHelpers.Combine(type, hasId, p.Id, isbuffered, length, posBytes, isEndBytes, totalLengthBytes, arrData); } else { b = ByteArrayHelpers.Combine(type, hasId, isbuffered, length, posBytes, isEndBytes, totalLengthBytes, arrData); } _stream.Write(b, 0, b.Length); }
internal List <PartialPacket> PayloadToPartials(int msgType, byte[] arrayToSplit, int chunckSize) { List <PartialPacket> splitted = new List <PartialPacket>(); int sourceArrayLength = arrayToSplit.Length; int wholePacketCount = sourceArrayLength / chunckSize; int lastPacketSize = sourceArrayLength % chunckSize; if (wholePacketCount == 0 && lastPacketSize <= 0) { return(null); } for (int i = 0; i < wholePacketCount; i++) { byte[] slice = new byte[chunckSize]; Array.Copy(arrayToSplit, i * chunckSize, slice, 0, MaxOutboundPacketSize); var partial = new PartialPacket { Type = msgType, Position = i, TotalDataSize = sourceArrayLength, Data = slice }; splitted.Add(partial); } if (lastPacketSize != 0) { byte[] slice = new byte[lastPacketSize]; Array.Copy(arrayToSplit, wholePacketCount * chunckSize, slice, 0, lastPacketSize); var partial = new PartialPacket { Type = msgType, Position = wholePacketCount, TotalDataSize = sourceArrayLength, Data = slice }; // Set last packet flag to this packet partial.IsEnd = true; splitted.Add(partial); } else { splitted.Last().IsEnd = true; } return(splitted); }
private async Task <PartialPacket> ReadPartialPacket(int dataLength) { PartialPacket partialPacket = new PartialPacket(); partialPacket.Position = await ReadInt(); partialPacket.IsEnd = await ReadBoolean(); partialPacket.TotalDataSize = await ReadInt(); // Read the data byte[] packetData = await ReadBytesAsync(dataLength); partialPacket.Data = packetData; return(partialPacket); }
/// <summary> /// Reads the bytes from the stream. /// </summary> private async Task Read() { try { while (true) { // Read type int type = await ReadByte(); // Read if the message is associated with an id bool hasId = await ReadBoolean(); byte[] id = null; if (hasId) { // The Id is a 128-bit guid id = await ReadBytesAsync(IdLength); } // Is this a partial reception ? bool isBuffered = await ReadBoolean(); // Read the size of the data int length = await ReadInt(); if (isBuffered) { // If it's a partial packet read the packet info PartialPacket partialPacket = await ReadPartialPacket(length); // todo property control if (!partialPacket.IsEnd) { _partialPacketBuffer.Add(partialPacket); if (_partialPacketBuffer.Count == 0) { _logger.Trace($"Received first packet: {partialPacket.Type}, total size: {partialPacket.TotalDataSize}."); } } else { // This is the last packet // Concat all data _partialPacketBuffer.Add(partialPacket); byte[] allData = ByteArrayHelpers.Combine(_partialPacketBuffer.Select(pp => pp.Data).ToArray()); _logger.Trace($"Received last packet: {_partialPacketBuffer.Count}, total length: {allData.Length}."); // Clear the buffer for the next partial to receive _partialPacketBuffer.Clear(); Message message; if (hasId) { message = new Message { Type = type, HasId = true, Id = id, Length = allData.Length, Payload = allData }; } else { message = new Message { Type = type, HasId = false, Length = allData.Length, Payload = allData }; } FireMessageReceivedEvent(message); } } else { // If it's not a partial packet the next "length" bytes should be // the entire data byte[] packetData = await ReadBytesAsync(length); Message message; if (hasId) { message = new Message { Type = type, HasId = true, Id = id, Length = length, Payload = packetData }; } else { message = new Message { Type = type, HasId = false, Length = length, Payload = packetData }; } FireMessageReceivedEvent(message); } } } catch (PeerDisconnectedException) { StreamClosed?.Invoke(this, EventArgs.Empty); Close(); } catch (Exception e) { if (!IsConnected && e is IOException) { // If the stream fails while the connection is logically closed (call to Close()) // we simply return - the StreamClosed event will no be closed. return; } Close(); StreamClosed?.Invoke(this, EventArgs.Empty); } }