private async Task <ReceiveMessageResult> receiveMessageAsync(ProtocolType protocol, int timeout, CancellationToken cancellationToken) { ReceiveMessageResult result = new ReceiveMessageResult { Bytes = 0, Packets = 0, Message = new Memory <byte>(), }; try { List <byte> receivedData = new List <byte>(); DateTime startTimestamp = DateTime.UtcNow; while (DateTime.UtcNow.Subtract(startTimestamp).TotalMilliseconds < timeout && receivedData.Count < TCPHeaderLength) { Memory <byte> buffer = new byte[1500]; TimeSpan receiveTimeout = TimeSpan.FromMilliseconds(timeout).Subtract(DateTime.UtcNow.Subtract(startTimestamp)); if (receiveTimeout.TotalMilliseconds >= 50) { int receivedBytes = await _client.ReceiveAsync(buffer, receiveTimeout, cancellationToken); if (receivedBytes > 0) { receivedData.AddRange(buffer.Slice(0, receivedBytes).ToArray()); result.Bytes += receivedBytes; result.Packets += 1; } } } if (receivedData.Count == 0) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC '" + RemoteHost + ":" + Port + "' - No Data was Received"); } if (receivedData.Count < TCPHeaderLength) { throw new UnitronicsException("Failed to Receive " + protocol + " Message within the Timeout Period from Unitronics PLC '" + RemoteHost + ":" + Port + "'"); } if (receivedData[3] != 0) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC '" + RemoteHost + ":" + Port + "' - The TCP Header was Invalid"); } if (BitConverter.ToUInt16(receivedData.GetRange(0, 2).ToArray(), 0) != _requestId) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC '" + RemoteHost + ":" + Port + "' - The TCP Header Transaction ID did not Match"); } if (receivedData[2] != (byte)protocol) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC '" + RemoteHost + ":" + Port + "' - The TCP Header Protocol Type did not Match"); } int tcpMessageDataLength = BitConverter.ToUInt16(new byte[] { receivedData[4], receivedData[5] }); if (tcpMessageDataLength <= 0 || tcpMessageDataLength > 1009) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC '" + RemoteHost + ":" + Port + "' - The TCP Message Length was Invalid"); } receivedData.RemoveRange(0, TCPHeaderLength); if (receivedData.Count < tcpMessageDataLength - TCPHeaderLength) { startTimestamp = DateTime.UtcNow; while (DateTime.UtcNow.Subtract(startTimestamp).TotalMilliseconds < timeout && receivedData.Count < tcpMessageDataLength) { Memory <byte> buffer = new byte[1024]; TimeSpan receiveTimeout = TimeSpan.FromMilliseconds(timeout).Subtract(DateTime.UtcNow.Subtract(startTimestamp)); if (receiveTimeout.TotalMilliseconds >= 50) { int receivedBytes = await _client.ReceiveAsync(buffer, receiveTimeout, cancellationToken); if (receivedBytes > 0) { receivedData.AddRange(buffer.Slice(0, receivedBytes).ToArray()); } result.Bytes += receivedBytes; result.Packets += 1; } } } if (receivedData.Count == 0) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC '" + RemoteHost + ":" + Port + "' - No Data was Received after TCP Header"); } if (receivedData.Count < tcpMessageDataLength - TCPHeaderLength) { throw new UnitronicsException("Failed to Receive " + protocol + " Message within the Timeout Period from Unitronics PLC '" + RemoteHost + ":" + Port + "'"); } result.Message = receivedData.ToArray(); } catch (ObjectDisposedException) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC '" + RemoteHost + ":" + Port + "' - The underlying Socket Connection has been Closed"); } catch (TimeoutException) { throw new UnitronicsException("Failed to Receive " + protocol + " Message within the Timeout Period from Unitronics PLC '" + RemoteHost + ":" + Port + "'"); } catch (System.Net.Sockets.SocketException e) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC '" + RemoteHost + ":" + Port + "'", e); } return(result); }
public async Task <ProcessMessageResult> ProcessMessageAsync(ReadOnlyMemory <byte> requestMessage, ProtocolType protocol, byte unitId, int timeout, int retries, CancellationToken cancellationToken) { int attempts = 0; Memory <byte> responseMessage = new Memory <byte>(); int bytesSent = 0; int packetsSent = 0; int bytesReceived = 0; int packetsReceived = 0; DateTime startTimestamp = DateTime.UtcNow; while (attempts <= retries) { try { if (!_semaphore.Wait(0)) { await _semaphore.WaitAsync(cancellationToken); } if (attempts > 0) { await destroyAndInitializeClient(timeout, cancellationToken); } // Send the Message SendMessageResult sendResult = await sendMessageAsync(requestMessage, protocol, timeout, cancellationToken); bytesSent += sendResult.Bytes; packetsSent += sendResult.Packets; // Receive a Response ReceiveMessageResult receiveResult = await receiveMessageAsync(protocol, timeout, cancellationToken); bytesReceived += receiveResult.Bytes; packetsReceived += receiveResult.Packets; responseMessage = receiveResult.Message; break; } catch (Exception) { if (attempts >= retries) { throw; } } finally { _semaphore.Release(); } // Increment the Attempts attempts++; } return(new ProcessMessageResult { BytesSent = bytesSent, PacketsSent = packetsSent, BytesReceived = bytesReceived, PacketsReceived = packetsReceived, Duration = DateTime.UtcNow.Subtract(startTimestamp).TotalMilliseconds, ResponseMessage = responseMessage, }); }
private async Task <ReceiveMessageResult> receiveMessageAsync(ProtocolType protocol, byte unitId, int timeout, CancellationToken cancellationToken) { ReceiveMessageResult result = new ReceiveMessageResult { Bytes = 0, Packets = 0, Message = new Memory <byte>(), }; try { List <byte> receivedData = new List <byte>(); DateTime startTimestamp = DateTime.UtcNow; bool receiveCompleted = false; while (DateTime.UtcNow.Subtract(startTimestamp).TotalMilliseconds < timeout && receiveCompleted == false) { Memory <byte> buffer = new byte[1500]; TimeSpan receiveTimeout = TimeSpan.FromMilliseconds(timeout).Subtract(DateTime.UtcNow.Subtract(startTimestamp)); if (receiveTimeout.TotalMilliseconds >= 50) { int receivedBytes = await _client.ReceiveAsync(buffer, receiveTimeout, cancellationToken); if (receivedBytes > 0) { receivedData.AddRange(buffer.Slice(0, receivedBytes).ToArray()); result.Bytes += receivedBytes; result.Packets += 1; } } receiveCompleted = isReceiveCompleted(protocol, receivedData); } if (receivedData.Count == 0) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "' - No Data was Received"); } if (receiveCompleted == false) { throw new UnitronicsException("Failed to Receive " + protocol + " Message within the Timeout Period from Unitronics PLC ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "'"); } result.Message = trimReceivedData(protocol, receivedData); } catch (ObjectDisposedException) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "' - The underlying Socket Connection has been Closed"); } catch (TimeoutException) { throw new UnitronicsException("Failed to Receive " + protocol + " Message within the Timeout Period from Unitronics PLC ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "'"); } catch (System.Net.Sockets.SocketException e) { throw new UnitronicsException("Failed to Receive " + protocol + " Message from Unitronics PLC ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "'", e); } return(result); }