Skip to content

Instantly share code, notes, and snippets.

@prettycode
Last active December 18, 2015 00:18
Show Gist options
  • Save prettycode/5695222 to your computer and use it in GitHub Desktop.
Save prettycode/5695222 to your computer and use it in GitHub Desktop.
Utility functions for NetworkStream reading operations.
using System;
using System.IO;
using System.Net.Sockets;
namespace prettycode.org
{
// Author: Chris O'Brien, prettycode.org
public static class NetworkStreamExtensions
{
/// <summary>
/// Read data from a NetworkStream's current position up to and including a "marker" sequence of
/// bytes. This method is blocking; it does not return a value until the stream has received and
/// read data ending with the marker.
/// </summary>
/// <param name="stream">The NetworkStream to read from.</param>
/// <param name="marker">The identifer to signal reading to stop.</param>
/// <returns>
/// The binary data read from the stream's current position up to and including the marker.
/// </returns>
public static byte[] ReadToMarker(this NetworkStream stream, byte[] marker)
{
#region Argument validation
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (!stream.CanRead)
{
throw new InvalidOperationException("'stream' does not support reading.");
}
if (marker == null)
{
throw new ArgumentNullException("marker");
}
if (marker.Length == 0)
{
throw new ArgumentOutOfRangeException("marker", "Must contain at least one byte.");
}
#endregion
var markerLength = marker.Length;
var lastMarkerByte = marker[markerLength - 1];
using (var packet = new MemoryStream())
{
byte currentByte;
while (true)
{
packet.WriteByte((currentByte = (byte)stream.ReadByte()));
if (packet.Position >= markerLength && currentByte == lastMarkerByte)
{
packet.Seek(-markerLength, SeekOrigin.Current);
for (var i = 0; i < markerLength; i++)
{
if (marker[i] != (byte)packet.ReadByte())
{
break;
}
if (i == markerLength - 1)
{
return packet.ToArray();
}
}
packet.Seek(0, SeekOrigin.End);
}
}
}
}
/// <summary>
/// <para>
/// Read a specified number of bytes from a NetworkStream's current position. This method is
/// blocking; it does not return a value until the stream has received and read the specified
/// number of bytes.
/// </para>
/// <para>
/// This behavior is distinct from NetworkStream.Read(byte[] buffer, int offset, int count),
/// where "count" is the number of bytes to read. The data read into "buffer" by
/// NetworkStream.Read is not guaranteed to be "count" in length if data of "count" length is not
/// avaialble in the stream. Unlike Read(), ReadBytes() will not return until it has read
/// "bytesToRead" number of bytes.
/// </para>
/// </summary>
/// <param name="stream">The NetworkStream to read from.</param>
/// <param name="bytesToRead">The number of bytes to read.</param>
/// <returns>A specified number of bytes read from the stream's current position.</returns>
public static byte[] ReadBytes(this NetworkStream stream, int bytesToRead, int bufferSize = 8192)
{
#region Argument validation
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (!stream.CanRead)
{
throw new InvalidOperationException("'stream' does not support reading.");
}
if (bytesToRead < 1)
{
throw new ArgumentOutOfRangeException("bytesToRead", "Must be 1 or greater.");
}
#endregion
using (var packet = new MemoryStream(bytesToRead))
{
byte[] buffer = new byte[bufferSize];
while (packet.Position < bytesToRead)
{
var bytesLeftToRead = bytesToRead - (int)packet.Position;
var bufferBytesToRead = (bytesLeftToRead > buffer.Length) ?
buffer.Length :
bytesLeftToRead;
packet.Write(buffer, 0, stream.Read(buffer, 0, bufferBytesToRead));
}
return packet.ToArray();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment