//******************************************************************************************************// FileClient.cs - Gbtc//// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://www.opensource.org/licenses/MIT//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 07/24/2006 - Pinal C. Patel// Original version of source code generated.// 09/06/2006 - J. Ritchie Carroll// Added bypass optimizations for high-speed file data access.// 09/29/2008 - J. Ritchie Carroll// Converted to C#.// 07/08/2009 - J. Ritchie Carroll// Added WaitHandle return value from asynchronous connection.// 09/14/2009 - Stephen C. Wills// Added new header and license agreement.// 06/23/2010 - Stephen C. Wills// Modified to use the absolute file path.// 11/29/2010 - Pinal C. Patel// Corrected the implementation of ConnectAsync() method.// 12/04/2010 - Pinal C. Patel// Removed locking around m_fileClient.Provider since it was unnecessary.////****************************************************************************************************** using System;using System.Collections.Generic;using System.ComponentModel;using System.IO;using System.Threading;using GSF.Configuration;using GSF.Diagnostics;using GSF.IO;using GSF.Threading; namespace GSF.Communication{ /// <summary> /// Represents a communication client based on <see cref="FileStream"/>. /// </summary> /// <example> /// This example shows how to use <see cref="FileClient"/> for writing data to a file: /// <code> /// using System; /// using GSF.Communication; /// /// class Program /// { /// static FileClient s_client; /// /// static void Main(string[] args) /// { /// // Initialize the client. /// s_client = new FileClient(@"File=c:\File.txt"); /// s_client.Initialize(); /// // Register event handlers. /// s_client.ConnectionAttempt += s_client_ConnectionAttempt; /// s_client.ConnectionEstablished += s_client_ConnectionEstablished; /// s_client.ConnectionTerminated += s_client_ConnectionTerminated; /// s_client.SendDataComplete += s_client_SendDataComplete; /// // Connect the client. /// s_client.Connect(); /// /// // Write user input to the file. /// string input; /// while (string.Compare(input = Console.ReadLine(), "Exit", true) != 0) /// { /// s_client.Send(input + "\r\n"); /// } /// /// // Disconnect the client on shutdown. /// s_client.Dispose(); /// } /// /// static void s_client_ConnectionAttempt(object sender, EventArgs e) /// { /// Console.WriteLine("Client is connecting to file."); /// } /// /// static void s_client_ConnectionEstablished(object sender, EventArgs e) /// { /// Console.WriteLine("Client connected to file."); /// } /// /// static void s_client_ConnectionTerminated(object sender, EventArgs e) /// { /// Console.WriteLine("Client disconnected from file."); /// } /// /// static void s_client_SendDataComplete(object sender, EventArgs e) /// { /// Console.WriteLine(string.Format("Sent data - {0}", s_client.TextEncoding.GetString(s_client.Client.SendBuffer))); /// } /// } /// </code> /// This example shows how to use <see cref="FileClient"/> for reading data to a file: /// <code> /// using System; /// using GSF; /// using GSF.Communication; /// /// class Program /// { /// static FileClient s_client; /// /// static void Main(string[] args) /// { /// // Initialize the client. /// s_client = new FileClient(@"File=c:\File.txt"); /// s_client.Initialize(); /// // Register event handlers. /// s_client.ConnectionAttempt += s_client_ConnectionAttempt; /// s_client.ConnectionEstablished += s_client_ConnectionEstablished; /// s_client.ConnectionTerminated += s_client_ConnectionTerminated; /// s_client.ReceiveDataComplete += s_client_ReceiveDataComplete; /// // Connect the client. /// s_client.Connect(); /// /// // Wait for client to read data. /// Console.ReadLine(); /// /// // Disconnect the client on shutdown. /// s_client.Dispose(); /// } /// /// static void s_client_ConnectionAttempt(object sender, EventArgs e) /// { /// Console.WriteLine("Client is connecting to file."); /// } /// /// static void s_client_ConnectionEstablished(object sender, EventArgs e) /// { /// Console.WriteLine("Client connected to file."); /// } /// /// static void s_client_ConnectionTerminated(object sender, EventArgs e) /// { /// Console.WriteLine("Client disconnected from file."); /// } /// /// static void s_client_ReceiveDataComplete(object sender, EventArgs<byte[], int> e) /// { /// Console.WriteLine(string.Format("Received data - {0}", s_client.TextEncoding.GetString(e.Argument1, 0, e.Argument2))); /// } /// } /// </code> /// </example> public class FileClient : ClientBase { #region [ Members ] // Constants /// <summary> /// Specifies the default value for the <see cref="AutoRepeat"/> property. /// </summary> public const bool DefaultAutoRepeat = false; /// <summary> /// Specifies the default value for the <see cref="ReceiveOnDemand"/> property. /// </summary> public const bool DefaultReceiveOnDemand = false; /// <summary> /// Specifies the default value for the <see cref="ReceiveInterval"/> property. /// </summary> public const int DefaultReceiveInterval = -1; /// <summary> /// Specifies the default value for the <see cref="StartingOffset"/> property. /// </summary> public const long DefaultStartingOffset = 0; /// <summary> /// Specifies the default value for the <see cref="FileOpenMode"/> property. /// </summary> public const FileMode DefaultFileOpenMode = FileMode.OpenOrCreate; /// <summary> /// Specifies the default value for the <see cref="FileShareMode"/> property. /// </summary> public const FileShare DefaultFileShareMode = FileShare.ReadWrite; /// <summary> /// Specifies the default value for the <see cref="FileAccessMode"/> property. /// </summary> public const FileAccess DefaultFileAccessMode = FileAccess.ReadWrite; /// <summary> /// Specifies the default value for the <see cref="ClientBase.ConnectionString"/> property. /// </summary> public const string DefaultConnectionString = "File=DataFile.txt"; // Fields private bool m_autoRepeat; private bool m_receiveOnDemand; private int m_receiveInterval; private long m_startingOffset; private FileMode m_fileOpenMode; private FileShare m_fileShareMode; private FileAccess m_fileAccessMode; private readonly TransportProvider<FileStream> m_fileClient; private Dictionary<string, string> m_connectData; private readonly SharedTimer m_receiveDataTimer; private ManualResetEvent m_connectionHandle;#if ThreadTracking private ManagedThread m_connectionThread;#else private Thread m_connectionThread;#endif private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Initializes a new instance of the <see cref="FileClient"/> class. /// </summary> public FileClient() : this(DefaultConnectionString) { } /// <summary> /// Initializes a new instance of the <see cref="FileClient"/> class. /// </summary> /// <param name="connectString">Connect string of the <see cref="FileClient"/>. See <see cref="DefaultConnectionString"/> for format.</param> public FileClient(string connectString) : base(TransportProtocol.File, connectString) { m_autoRepeat = DefaultAutoRepeat; m_receiveOnDemand = DefaultReceiveOnDemand; m_receiveInterval = DefaultReceiveInterval; m_startingOffset = DefaultStartingOffset; m_fileOpenMode = DefaultFileOpenMode; m_fileShareMode = DefaultFileShareMode; m_fileAccessMode = DefaultFileAccessMode; m_fileClient = new TransportProvider<FileStream>(); m_receiveDataTimer = s_timerScheduler.CreateTimer(); m_receiveDataTimer.Elapsed += m_receiveDataTimer_Elapsed; } /// <summary> /// Initializes a new instance of the <see cref="FileClient"/> class. /// </summary> /// <param name="container"><see cref="IContainer"/> object that contains the <see cref="FileClient"/>.</param> public FileClient(IContainer container) : this() { if (container != null) container.Add(this); } #endregion #region [ Properties ] /// <summary> /// Gets or sets a boolean value that indicates whether receiving (reading) of data is to be repeated endlessly. /// </summary> /// <exception cref="InvalidOperationException"><see cref="AutoRepeat"/> is enabled when <see cref="FileAccessMode"/> is <see cref="FileAccess.ReadWrite"/></exception> [Category("Data"), DefaultValue(DefaultAutoRepeat), Description("Indicates whether receiving (reading) of data is to be repeated endlessly.")] public bool AutoRepeat { get { return m_autoRepeat; } set { if (value && m_fileAccessMode == FileAccess.ReadWrite) throw new InvalidOperationException("AutoRepeat cannot be enabled when FileAccessMode is FileAccess.ReadWrite"); m_autoRepeat = value; } } /// <summary> /// Gets or sets a boolean value that indicates whether receiving (reading) of data will be initiated manually by calling <see cref="ReadNextBuffer"/>. /// </summary> /// <remarks> /// <see cref="ReceiveInterval"/> will be set to -1 when <see cref="ReceiveOnDemand"/> is enabled. /// </remarks> [Category("Data"), DefaultValue(DefaultReceiveOnDemand), Description("Indicates whether receiving (reading) of data will be initiated manually by calling ReceiveData().")] public bool ReceiveOnDemand { get { return m_receiveOnDemand; } set { m_receiveOnDemand = value; // We'll disable receiving data at a set interval if user wants to receive data on demand. if (m_receiveOnDemand) m_receiveInterval = -1; } } /// <summary> /// Gets or sets the number of milliseconds to pause before receiving (reading) the next available set of data. /// </summary> /// <remarks> /// Set <see cref="ReceiveInterval"/> = -1 to receive (read) data continuously without pausing. /// </remarks> [Category("Data"), DefaultValue(DefaultReceiveInterval), Description("The number of milliseconds to pause before receiving (reading) the next available set of data. Set ReceiveInterval = -1 to receive data continuously without pausing.")] public double ReceiveInterval { get { return m_receiveInterval; } set { m_receiveInterval = value < 1.0D ? - 1 : (int)value; } } /// <summary> /// Gets or sets the starting point relative to the beginning of the file from where the data is to be received (read). /// </summary> /// <exception cref="ArgumentException">The value being assigned is not a positive number.</exception> [Category("File"), DefaultValue(DefaultStartingOffset), Description("The starting point relative to the beginning of the file from where the data is to be received (read).")] public long StartingOffset { get { return m_startingOffset; } set { if (value < 0) throw new ArgumentException("Value must be positive"); m_startingOffset = value; } } /// <summary> /// Gets or sets the <see cref="FileMode"/> value to be used when opening the file. /// </summary> [Category("File"), DefaultValue(DefaultFileOpenMode), Description("The System.IO.FileMode value to be used when opening the file.")] public FileMode FileOpenMode { get { return m_fileOpenMode; } set { m_fileOpenMode = value; } } /// <summary> /// Gets or set the <see cref="FileShare"/> value to be used when opening the file. /// </summary> [Category("File"), DefaultValue(DefaultFileShareMode), Description("The System.IO.FileShare value to be used when opening the file.")] public FileShare FileShareMode { get { return m_fileShareMode; } set { m_fileShareMode = value; } } /// <summary> /// Gets or sets the <see cref="FileAccess"/> value to be used when opening the file. /// </summary> /// <exception cref="InvalidOperationException"><see cref="FileAccessMode"/> is set to <see cref="FileAccess.ReadWrite"/> when <see cref="AutoRepeat"/> is enabled.</exception> [Category("File"), DefaultValue(DefaultFileAccessMode), Description("The System.IO.FileAccess value to be used when opening the file.")] public FileAccess FileAccessMode { get { return m_fileAccessMode; } set { if (value == FileAccess.ReadWrite && m_autoRepeat) throw new InvalidOperationException("FileAccessMode cannot be set to FileAccess.ReadWrite when AutoRepeat is enabled"); m_fileAccessMode = value; } } /// <summary> /// Gets the <see cref="FileStream"/> object for the <see cref="FileClient"/>. /// </summary> [Browsable(false)] public FileStream Client => m_fileClient.Provider; /// <summary> /// Gets the server URI of the <see cref="FileClient"/>. /// </summary> [Browsable(false)] public override string ServerUri => $"{TransportProtocol}://{m_connectData["file"]}".ToLower(); #endregion #region [ Methods ] /// <summary> /// Reads a number of bytes from the current received data buffer and writes those bytes into a byte array at the specified offset. /// </summary> /// <param name="buffer">Destination buffer used to hold copied bytes.</param> /// <param name="startIndex">0-based starting index into destination <paramref name="buffer"/> to begin writing data.</param> /// <param name="length">The number of bytes to read from current received data buffer and write into <paramref name="buffer"/>.</param> /// <returns>The number of bytes read.</returns> /// <remarks> /// This function should only be called from within the <see cref="ClientBase.ReceiveData"/> event handler. Calling this method outside /// this event will have unexpected results. /// </remarks> /// <exception cref="InvalidOperationException">No received data buffer has been defined to read.</exception> /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> or <paramref name="length"/> is less than 0 -or- /// <paramref name="startIndex"/> and <paramref name="length"/> will exceed <paramref name="buffer"/> length. /// </exception> public override int Read(byte[] buffer, int startIndex, int length) { buffer.ValidateParameters(startIndex, length); if ((object)m_fileClient.ReceiveBuffer != null) { int sourceLength = m_fileClient.BytesReceived - ReadIndex; int readBytes = length > sourceLength ? sourceLength : length; Buffer.BlockCopy(m_fileClient.ReceiveBuffer, ReadIndex, buffer, startIndex, readBytes); // Update read index for next call ReadIndex += readBytes; if (ReadIndex >= m_fileClient.BytesReceived) ReadIndex = 0; return readBytes; } throw new InvalidOperationException("No received data buffer has been defined to read."); } /// <summary> /// Reads next data buffer from the <see cref="FileStream"/>. /// </summary> /// <exception cref="InvalidOperationException"><see cref="ReadNextBuffer"/> is called when <see cref="FileClient"/> is not connected.</exception> /// <exception cref="InvalidOperationException"><see cref="ReadNextBuffer"/> is called when <see cref="ReceiveOnDemand"/> is disabled.</exception> public void ReadNextBuffer() { if (m_receiveOnDemand) { if (CurrentState == ClientState.Connected) ReadData(); else throw new InvalidOperationException("Client is currently not connected"); } else { throw new InvalidOperationException("ReadNextBuffer() cannot be used when ReceiveOnDemand is disabled"); } } /// <summary> /// Disconnects the <see cref="FileClient"/> from the <see cref="FileStream"/>. /// </summary> public override void Disconnect() { if (CurrentState != ClientState.Disconnected) {Lines 1–500 of 793. Load more
//****************************************************************************************************** // FileClient.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 07/24/2006 - Pinal C. Patel // Original version of source code generated. // 09/06/2006 - J. Ritchie Carroll // Added bypass optimizations for high-speed file data access. // 09/29/2008 - J. Ritchie Carroll // Converted to C#. // 07/08/2009 - J. Ritchie Carroll // Added WaitHandle return value from asynchronous connection. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 06/23/2010 - Stephen C. Wills // Modified to use the absolute file path. // 11/29/2010 - Pinal C. Patel // Corrected the implementation of ConnectAsync() method. // 12/04/2010 - Pinal C. Patel // Removed locking around m_fileClient.Provider since it was unnecessary. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Threading; using GSF.Configuration; using GSF.Diagnostics; using GSF.IO; using GSF.Threading; namespace GSF.Communication { /// <summary> /// Represents a communication client based on <see cref="FileStream"/>. /// </summary> /// <example> /// This example shows how to use <see cref="FileClient"/> for writing data to a file: /// <code> /// using System; /// using GSF.Communication; /// /// class Program /// { /// static FileClient s_client; /// /// static void Main(string[] args) /// { /// // Initialize the client. /// s_client = new FileClient(@"File=c:\File.txt"); /// s_client.Initialize(); /// // Register event handlers. /// s_client.ConnectionAttempt += s_client_ConnectionAttempt; /// s_client.ConnectionEstablished += s_client_ConnectionEstablished; /// s_client.ConnectionTerminated += s_client_ConnectionTerminated; /// s_client.SendDataComplete += s_client_SendDataComplete; /// // Connect the client. /// s_client.Connect(); /// /// // Write user input to the file. /// string input; /// while (string.Compare(input = Console.ReadLine(), "Exit", true) != 0) /// { /// s_client.Send(input + "\r\n"); /// } /// /// // Disconnect the client on shutdown. /// s_client.Dispose(); /// } /// /// static void s_client_ConnectionAttempt(object sender, EventArgs e) /// { /// Console.WriteLine("Client is connecting to file."); /// } /// /// static void s_client_ConnectionEstablished(object sender, EventArgs e) /// { /// Console.WriteLine("Client connected to file."); /// } /// /// static void s_client_ConnectionTerminated(object sender, EventArgs e) /// { /// Console.WriteLine("Client disconnected from file."); /// } /// /// static void s_client_SendDataComplete(object sender, EventArgs e) /// { /// Console.WriteLine(string.Format("Sent data - {0}", s_client.TextEncoding.GetString(s_client.Client.SendBuffer))); /// } /// } /// </code> /// This example shows how to use <see cref="FileClient"/> for reading data to a file: /// <code> /// using System; /// using GSF; /// using GSF.Communication; /// /// class Program /// { /// static FileClient s_client; /// /// static void Main(string[] args) /// { /// // Initialize the client. /// s_client = new FileClient(@"File=c:\File.txt"); /// s_client.Initialize(); /// // Register event handlers. /// s_client.ConnectionAttempt += s_client_ConnectionAttempt; /// s_client.ConnectionEstablished += s_client_ConnectionEstablished; /// s_client.ConnectionTerminated += s_client_ConnectionTerminated; /// s_client.ReceiveDataComplete += s_client_ReceiveDataComplete; /// // Connect the client. /// s_client.Connect(); /// /// // Wait for client to read data. /// Console.ReadLine(); /// /// // Disconnect the client on shutdown. /// s_client.Dispose(); /// } /// /// static void s_client_ConnectionAttempt(object sender, EventArgs e) /// { /// Console.WriteLine("Client is connecting to file."); /// } /// /// static void s_client_ConnectionEstablished(object sender, EventArgs e) /// { /// Console.WriteLine("Client connected to file."); /// } /// /// static void s_client_ConnectionTerminated(object sender, EventArgs e) /// { /// Console.WriteLine("Client disconnected from file."); /// } /// /// static void s_client_ReceiveDataComplete(object sender, EventArgs<byte[], int> e) /// { /// Console.WriteLine(string.Format("Received data - {0}", s_client.TextEncoding.GetString(e.Argument1, 0, e.Argument2))); /// } /// } /// </code> /// </example> public class FileClient : ClientBase { #region [ Members ] // Constants /// <summary> /// Specifies the default value for the <see cref="AutoRepeat"/> property. /// </summary> public const bool DefaultAutoRepeat = false; /// <summary> /// Specifies the default value for the <see cref="ReceiveOnDemand"/> property. /// </summary> public const bool DefaultReceiveOnDemand = false; /// <summary> /// Specifies the default value for the <see cref="ReceiveInterval"/> property. /// </summary> public const int DefaultReceiveInterval = -1; /// <summary> /// Specifies the default value for the <see cref="StartingOffset"/> property. /// </summary> public const long DefaultStartingOffset = 0; /// <summary> /// Specifies the default value for the <see cref="FileOpenMode"/> property. /// </summary> public const FileMode DefaultFileOpenMode = FileMode.OpenOrCreate; /// <summary> /// Specifies the default value for the <see cref="FileShareMode"/> property. /// </summary> public const FileShare DefaultFileShareMode = FileShare.ReadWrite; /// <summary> /// Specifies the default value for the <see cref="FileAccessMode"/> property. /// </summary> public const FileAccess DefaultFileAccessMode = FileAccess.ReadWrite; /// <summary> /// Specifies the default value for the <see cref="ClientBase.ConnectionString"/> property. /// </summary> public const string DefaultConnectionString = "File=DataFile.txt"; // Fields private bool m_autoRepeat; private bool m_receiveOnDemand; private int m_receiveInterval; private long m_startingOffset; private FileMode m_fileOpenMode; private FileShare m_fileShareMode; private FileAccess m_fileAccessMode; private readonly TransportProvider<FileStream> m_fileClient; private Dictionary<string, string> m_connectData; private readonly SharedTimer m_receiveDataTimer; private ManualResetEvent m_connectionHandle; #if ThreadTracking private ManagedThread m_connectionThread; #else private Thread m_connectionThread; #endif private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Initializes a new instance of the <see cref="FileClient"/> class. /// </summary> public FileClient() : this(DefaultConnectionString) { } /// <summary> /// Initializes a new instance of the <see cref="FileClient"/> class. /// </summary> /// <param name="connectString">Connect string of the <see cref="FileClient"/>. See <see cref="DefaultConnectionString"/> for format.</param> public FileClient(string connectString) : base(TransportProtocol.File, connectString) { m_autoRepeat = DefaultAutoRepeat; m_receiveOnDemand = DefaultReceiveOnDemand; m_receiveInterval = DefaultReceiveInterval; m_startingOffset = DefaultStartingOffset; m_fileOpenMode = DefaultFileOpenMode; m_fileShareMode = DefaultFileShareMode; m_fileAccessMode = DefaultFileAccessMode; m_fileClient = new TransportProvider<FileStream>(); m_receiveDataTimer = s_timerScheduler.CreateTimer(); m_receiveDataTimer.Elapsed += m_receiveDataTimer_Elapsed; } /// <summary> /// Initializes a new instance of the <see cref="FileClient"/> class. /// </summary> /// <param name="container"><see cref="IContainer"/> object that contains the <see cref="FileClient"/>.</param> public FileClient(IContainer container) : this() { if (container != null) container.Add(this); } #endregion #region [ Properties ] /// <summary> /// Gets or sets a boolean value that indicates whether receiving (reading) of data is to be repeated endlessly. /// </summary> /// <exception cref="InvalidOperationException"><see cref="AutoRepeat"/> is enabled when <see cref="FileAccessMode"/> is <see cref="FileAccess.ReadWrite"/></exception> [Category("Data"), DefaultValue(DefaultAutoRepeat), Description("Indicates whether receiving (reading) of data is to be repeated endlessly.")] public bool AutoRepeat { get { return m_autoRepeat; } set { if (value && m_fileAccessMode == FileAccess.ReadWrite) throw new InvalidOperationException("AutoRepeat cannot be enabled when FileAccessMode is FileAccess.ReadWrite"); m_autoRepeat = value; } } /// <summary> /// Gets or sets a boolean value that indicates whether receiving (reading) of data will be initiated manually by calling <see cref="ReadNextBuffer"/>. /// </summary> /// <remarks> /// <see cref="ReceiveInterval"/> will be set to -1 when <see cref="ReceiveOnDemand"/> is enabled. /// </remarks> [Category("Data"), DefaultValue(DefaultReceiveOnDemand), Description("Indicates whether receiving (reading) of data will be initiated manually by calling ReceiveData().")] public bool ReceiveOnDemand { get { return m_receiveOnDemand; } set { m_receiveOnDemand = value; // We'll disable receiving data at a set interval if user wants to receive data on demand. if (m_receiveOnDemand) m_receiveInterval = -1; } } /// <summary> /// Gets or sets the number of milliseconds to pause before receiving (reading) the next available set of data. /// </summary> /// <remarks> /// Set <see cref="ReceiveInterval"/> = -1 to receive (read) data continuously without pausing. /// </remarks> [Category("Data"), DefaultValue(DefaultReceiveInterval), Description("The number of milliseconds to pause before receiving (reading) the next available set of data. Set ReceiveInterval = -1 to receive data continuously without pausing.")] public double ReceiveInterval { get { return m_receiveInterval; } set { m_receiveInterval = value < 1.0D ? - 1 : (int)value; } } /// <summary> /// Gets or sets the starting point relative to the beginning of the file from where the data is to be received (read). /// </summary> /// <exception cref="ArgumentException">The value being assigned is not a positive number.</exception> [Category("File"), DefaultValue(DefaultStartingOffset), Description("The starting point relative to the beginning of the file from where the data is to be received (read).")] public long StartingOffset { get { return m_startingOffset; } set { if (value < 0) throw new ArgumentException("Value must be positive"); m_startingOffset = value; } } /// <summary> /// Gets or sets the <see cref="FileMode"/> value to be used when opening the file. /// </summary> [Category("File"), DefaultValue(DefaultFileOpenMode), Description("The System.IO.FileMode value to be used when opening the file.")] public FileMode FileOpenMode { get { return m_fileOpenMode; } set { m_fileOpenMode = value; } } /// <summary> /// Gets or set the <see cref="FileShare"/> value to be used when opening the file. /// </summary> [Category("File"), DefaultValue(DefaultFileShareMode), Description("The System.IO.FileShare value to be used when opening the file.")] public FileShare FileShareMode { get { return m_fileShareMode; } set { m_fileShareMode = value; } } /// <summary> /// Gets or sets the <see cref="FileAccess"/> value to be used when opening the file. /// </summary> /// <exception cref="InvalidOperationException"><see cref="FileAccessMode"/> is set to <see cref="FileAccess.ReadWrite"/> when <see cref="AutoRepeat"/> is enabled.</exception> [Category("File"), DefaultValue(DefaultFileAccessMode), Description("The System.IO.FileAccess value to be used when opening the file.")] public FileAccess FileAccessMode { get { return m_fileAccessMode; } set { if (value == FileAccess.ReadWrite && m_autoRepeat) throw new InvalidOperationException("FileAccessMode cannot be set to FileAccess.ReadWrite when AutoRepeat is enabled"); m_fileAccessMode = value; } } /// <summary> /// Gets the <see cref="FileStream"/> object for the <see cref="FileClient"/>. /// </summary> [Browsable(false)] public FileStream Client => m_fileClient.Provider; /// <summary> /// Gets the server URI of the <see cref="FileClient"/>. /// </summary> [Browsable(false)] public override string ServerUri => $"{TransportProtocol}://{m_connectData["file"]}".ToLower(); #endregion #region [ Methods ] /// <summary> /// Reads a number of bytes from the current received data buffer and writes those bytes into a byte array at the specified offset. /// </summary> /// <param name="buffer">Destination buffer used to hold copied bytes.</param> /// <param name="startIndex">0-based starting index into destination <paramref name="buffer"/> to begin writing data.</param> /// <param name="length">The number of bytes to read from current received data buffer and write into <paramref name="buffer"/>.</param> /// <returns>The number of bytes read.</returns> /// <remarks> /// This function should only be called from within the <see cref="ClientBase.ReceiveData"/> event handler. Calling this method outside /// this event will have unexpected results. /// </remarks> /// <exception cref="InvalidOperationException">No received data buffer has been defined to read.</exception> /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> or <paramref name="length"/> is less than 0 -or- /// <paramref name="startIndex"/> and <paramref name="length"/> will exceed <paramref name="buffer"/> length. /// </exception> public override int Read(byte[] buffer, int startIndex, int length) { buffer.ValidateParameters(startIndex, length); if ((object)m_fileClient.ReceiveBuffer != null) { int sourceLength = m_fileClient.BytesReceived - ReadIndex; int readBytes = length > sourceLength ? sourceLength : length; Buffer.BlockCopy(m_fileClient.ReceiveBuffer, ReadIndex, buffer, startIndex, readBytes); // Update read index for next call ReadIndex += readBytes; if (ReadIndex >= m_fileClient.BytesReceived) ReadIndex = 0; return readBytes; } throw new InvalidOperationException("No received data buffer has been defined to read."); } /// <summary> /// Reads next data buffer from the <see cref="FileStream"/>. /// </summary> /// <exception cref="InvalidOperationException"><see cref="ReadNextBuffer"/> is called when <see cref="FileClient"/> is not connected.</exception> /// <exception cref="InvalidOperationException"><see cref="ReadNextBuffer"/> is called when <see cref="ReceiveOnDemand"/> is disabled.</exception> public void ReadNextBuffer() { if (m_receiveOnDemand) { if (CurrentState == ClientState.Connected) ReadData(); else throw new InvalidOperationException("Client is currently not connected"); } else { throw new InvalidOperationException("ReadNextBuffer() cannot be used when ReceiveOnDemand is disabled"); } } /// <summary> /// Disconnects the <see cref="FileClient"/> from the <see cref="FileStream"/>. /// </summary> public override void Disconnect() { if (CurrentState != ClientState.Disconnected) {