/// <summary> /// Internal method which reacts on incoming bytes on the currently active socket connection. /// Only one of this connection is active at one time. /// </summary> protected async Task RunReceiveLoopAsync(IDisposable parentDisposable, Socket socket, IPEndPoint localEndPoint, IPEndPoint partnerEndPoint, CancellationToken cancelToken) { parentDisposable.MustNotBeNull(nameof(parentDisposable)); socket.MustNotBeNull(nameof(socket)); localEndPoint.MustNotBeNull(nameof(localEndPoint)); partnerEndPoint.MustNotBeNull(nameof(partnerEndPoint)); _lastSuccessfulConnectTimestampUtc = DateTime.UtcNow; var localEndPointStr = localEndPoint.ToString(); var partnerEndPointStr = partnerEndPoint.ToString(); var newConnection = true; if (this.IsLoggerSet) { this.Log( LoggingMessageType.Info, StringBuffer.Format("Starting receive loop for connection {0} to {1}", localEndPointStr, partnerEndPointStr)); } var receiveBuffer = new byte[this.ReceiveBufferSize]; while (!cancelToken.IsCancellationRequested) { int lastReceiveResult; try { // Read next bytes #if NETSTANDARD2_0 var receiveTask = socket.ReceiveAsync(new ArraySegment <byte>(receiveBuffer), SocketFlags.None); if (receiveTask.IsCompleted) { lastReceiveResult = receiveTask.Result; } else if (this.ReceiveTimeout == TimeSpan.Zero) { lastReceiveResult = await receiveTask .ConfigureAwait(false); } else { var timeoutTask = Task.Delay(this.ReceiveTimeout); await Task.WhenAny(receiveTask, timeoutTask) .ConfigureAwait(false); if (receiveTask.IsCompleted) { lastReceiveResult = receiveTask.Result; } else { _ = receiveTask.ContinueWith(s_dummyReceiveContinuation); if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format( "Timeout while receiving from {0}!", partnerEndPointStr)); } break; } } #else var receiveTaskStruct = socket.ReceiveAsync(new Memory <byte>(receiveBuffer), SocketFlags.None); if (receiveTaskStruct.IsCompleted) { lastReceiveResult = receiveTaskStruct.Result; } else if (this.ReceiveTimeout == TimeSpan.Zero) { lastReceiveResult = await receiveTaskStruct .ConfigureAwait(false); } else { var receiveTask = receiveTaskStruct.AsTask(); var timeoutTask = Task.Delay(this.ReceiveTimeout); await Task.WhenAny(receiveTask, timeoutTask) .ConfigureAwait(false); if (receiveTask.IsCompleted) { lastReceiveResult = receiveTask.Result; } else { _ = receiveTask.ContinueWith(s_dummyReceiveContinuation); if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format( "Timeout while receiving from {0}!", partnerEndPointStr)); } break; } } #endif // Reset receive result if we where canceled already if (lastReceiveResult == 0) { this.Log(LoggingMessageType.Info, "Connection closed by remote partner"); } else if (cancelToken.IsCancellationRequested) { this.Log(LoggingMessageType.Info, "Connection canceled by local program"); lastReceiveResult = 0; } else { _lastSuccessfulReceiveTimestampUtc = DateTime.UtcNow; } } catch (ObjectDisposedException) { break; } catch (SocketException socketException) { if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format( "Error while receiving bytes from {0}: (Code: {1}) {2}", partnerEndPointStr, socketException.SocketErrorCode.ToString(), socketException.Message), exception: socketException); } break; } catch (Exception ex) { if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format( "Error while receiving bytes from {0}: {1}", partnerEndPointStr, ex.Message), exception: ex); } break; } if (lastReceiveResult <= 0) { break; } this.ProcessReceivedBytes(newConnection, receiveBuffer, lastReceiveResult); newConnection = false; } // Ensure that the socket is closed after ending this method TcpAsyncUtil.SafeDispose(parentDisposable); }