/// <summary> /// Whaiting for previous package receiving by client. /// </summary> /// <param name="stream">Stream to client.</param> /// <param name="mode">Mode of stram managing.</param> /// <returns></returns> public static bool WaitPackageReceiving(Stream stream, StreamChanelMode mode) { switch (mode) { case StreamChanelMode.Oneway: Thread.SpinWait(OneWaySpinsPause); break; case StreamChanelMode.Duplex: // Open stream reader. BinaryReader sr = new BinaryReader(stream); byte[] header = new byte[HEADER_SIZE]; // Bufer that would contain stream header. int blockIndex; // Buffer that would contain current stream block. #region Wait new package // Wait data flush. while (true) { lock (stream) { // Compute current index block. sr.BaseStream.Position = 0; sr.Read(header, 0, HEADER_SIZE); } blockIndex = BitConverter.ToInt32(header, 0); // Drop if next block request. if (blockIndex == -1) { break; } // Wait. Thread.Sleep(5); } #endregion break; } return(true); }
/// <summary> /// Informing server about receiving message by client. /// </summary> /// <param name="mode">Server mode that decide reaction.</param> /// <param name="stream">Target to server stream.</param> public static void InformAboutReceving(StreamChanelMode mode, Stream stream) { lock (stream) { // Inform server that data recevied. if (mode == StreamChanelMode.Duplex) { stream.Position = 0; // Build answer. byte[] binaryData = new byte[4]; // Add next index as query. Array.Copy(BitConverter.GetBytes(-1), 0, binaryData, 0, 4); // Send data. stream.Write(binaryData, 0, 4); stream.Flush(); Thread.Sleep(5); } } }
/// <summary> /// Writing asynchronicly binary data to stream. /// </summary> /// <param name="stream">Target stream.</param> /// <param name="mode"> /// Defines mode of package building. /// In case of Duplex streaming would droped if @MilisecondsBeforeDrop timeout passed without client's confirmation. /// </param> /// <param name="data">Binary data that would be sent to stream.</param> /// <param name="dataBlockSize">Size of block in bytes that would be send to stream per each flush.</param> /// <returns>Asynchronous operation of data writing.</returns> public static async Task StreamWriterAsync(Stream stream, StreamChanelMode mode, byte[] data, int dataBlockSize = 610000) { await Task.Yield(); // Open stream writer. BinaryWriter sw = new BinaryWriter(stream); // Send data size. lock (stream) { // Start writing from 0. sw.BaseStream.Position = 0; // Get binary data. byte[] binaryData = new byte[12]; // Set data length to header. Array.Copy(BitConverter.GetBytes(data.Length), 0, binaryData, 0, 4); // Set data length to header. Array.Copy(BitConverter.GetBytes(dataBlockSize), 0, binaryData, 4, 4); // Set data length to header. Array.Copy(BitConverter.GetBytes((int)mode), 0, binaryData, 8, 4); // Add data to package. BuildPackage(0, 0, HEADER_SIZE + 12, binaryData, out byte[] sharedData); // Sending data. sw.BaseStream.Write(sharedData, 0, sharedData.Length); sw.BaseStream.Flush(); } // Wait before sending next package. WaitPackageReceiving(stream, mode); // Compute count of packages. int packagesCount = ComputeRequiredPackages(dataBlockSize, data.Length); for (int orderIndex = 0; orderIndex < packagesCount; orderIndex++) { int packageIndex = orderIndex + 1; lock (stream) { // Start writing from 0. sw.BaseStream.Position = 0; // Building package. BuildPackage(orderIndex, packageIndex, dataBlockSize, data, out byte[] package); // Sending package to stream. sw.BaseStream.Write(package, 0, package.Length); // Release data to underlaying device. sw.BaseStream.Flush(); } // Wait before sending next package. WaitPackageReceiving(stream, mode); } // Releasing unmanaged memory. sw.Dispose(); }