From c6d20bcc6af36a3759bc462025161fe71e77b39f Mon Sep 17 00:00:00 2001 From: Jonas Arnold Date: Wed, 10 May 2023 11:36:49 +0200 Subject: [PATCH] Improved stability of Tcp/Udp Reading/Writing --- MultiTerm.Protocols/CommunicationProtocol.cs | 2 +- MultiTerm.Protocols/Tcp/TcpClientProtocol.cs | 12 +++++++++ MultiTerm.Protocols/Udp/UdpProtocol.cs | 26 +++++++++++++++++--- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/MultiTerm.Protocols/CommunicationProtocol.cs b/MultiTerm.Protocols/CommunicationProtocol.cs index cb68dd2..1ddf17a 100644 --- a/MultiTerm.Protocols/CommunicationProtocol.cs +++ b/MultiTerm.Protocols/CommunicationProtocol.cs @@ -151,7 +151,7 @@ public abstract class CommunicationProtocol : ICommunicationProtocol else { this.logger.LogWarn($"'{nameof(Connect)}()' failed to connect to protocol, did not start reading thread.", nameof(CommunicationProtocol)); - this.messenger.Send(new GenericUserInterfaceMessage("Failed to connect to protocol, for more information please check logfile.", MessageImportance.High)); + this.messenger.Send(new GenericUserInterfaceMessage($"Failed to connect to '{this.GetProtocolAndInstanceIdentifier()}'. For more information please check logfile.", MessageImportance.High)); return false; } } diff --git a/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs b/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs index 64cd407..7378448 100644 --- a/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs +++ b/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs @@ -134,6 +134,18 @@ public class TcpClientProtocol : CommunicationProtocol this.OnUnintentionallyDisconnected(); break; // break loop } + catch (IOException ioEx) + { + // socket exception and timeout => normal use case + if (ioEx.InnerException is SocketException sockEx && sockEx?.SocketErrorCode == SocketError.TimedOut) { } + // other IO Exception + else + { + this.logger.LogException(ioEx, $"IOException while reading data in {nameof(InternalRead)}", nameof(TcpClientProtocol)); + this.messenger.Send(new StoppedReadingUIMessage(this, ioEx.ToString())); + break; // break loop + } + } catch (Exception ex) { this.logger.LogException(ex, $"Exception while reading data in {nameof(InternalRead)}", nameof(TcpClientProtocol)); diff --git a/MultiTerm.Protocols/Udp/UdpProtocol.cs b/MultiTerm.Protocols/Udp/UdpProtocol.cs index c948668..353c35c 100644 --- a/MultiTerm.Protocols/Udp/UdpProtocol.cs +++ b/MultiTerm.Protocols/Udp/UdpProtocol.cs @@ -5,6 +5,7 @@ using MultiTerm.Protocols.Helpers; using MultiTerm.Protocols.Model; using MultiTerm.Protocols.Network; using MultiTerm.Protocols.Types; +using System.Net; using System.Net.Sockets; namespace MultiTerm.Protocols.Udp; @@ -19,6 +20,9 @@ public class UdpProtocol : CommunicationProtocol private UdpClient? receivingUdpClient; private UdpClient? sendingUdpClient; + private const int ReadTimeoutMs = 100; // milliseconds until the read operation timeouts + private const int WriteTimeoutMs = 100; // milliseconds until the write operation timeouts + public UdpProtocol(ILogger logger, IMessenger messenger) : base(logger, messenger) { } protected override bool InternalConnect(IProtocolSettings settings) @@ -74,6 +78,10 @@ public class UdpProtocol : CommunicationProtocol return false; } + // set static settings + this.receivingUdpClient.Client.ReceiveTimeout = ReadTimeoutMs; + this.sendingUdpClient.Client.SendTimeout = WriteTimeoutMs; + return true; } @@ -101,14 +109,15 @@ public class UdpProtocol : CommunicationProtocol protected override void InternalRead(CancellationToken ct) { - while(ct.IsCancellationRequested == false) + while (ct.IsCancellationRequested == false) { // try receive message - UdpReceiveResult receivedResult; + IPEndPoint? remoteEndPoint = null; + byte[] receivedBytes = Array.Empty(); try { // will throw ObjectDisposedException if null - receivedResult = this.receivingUdpClient!.ReceiveAsync(ct).GetAwaiter().GetResult(); + receivedBytes = this.receivingUdpClient!.Receive(ref remoteEndPoint); } catch (OperationCanceledException) // intentionally cancelled => just break { @@ -120,6 +129,16 @@ public class UdpProtocol : CommunicationProtocol this.OnUnintentionallyDisconnected(); break; // break loop } + catch (SocketException sockEx) + { + // timeout = normal use case + if (sockEx.SocketErrorCode != SocketError.TimedOut) + { + this.logger.LogException(sockEx, $"SocketException while reading data in {nameof(InternalRead)}", nameof(UdpProtocol)); + this.messenger.Send(new StoppedReadingUIMessage(this, sockEx.SocketErrorCode.ToString())); + break; // break loop + } + } catch (Exception ex) { this.logger.LogException(ex, $"Exception while reading data in {nameof(InternalRead)}", nameof(UdpProtocol)); @@ -128,7 +147,6 @@ public class UdpProtocol : CommunicationProtocol } // any data received? - byte[] receivedBytes = receivedResult.Buffer; if (receivedBytes.Length > 0) { foreach (byte b in receivedBytes)