Last active
December 18, 2015 00:18
-
-
Save prettycode/5695222 to your computer and use it in GitHub Desktop.
Utility functions for NetworkStream reading operations.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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