private async Task ProcessSends() { // Resolve `output` PipeReader via the IDuplexPipe interface prior to loop start for performance. var output = Output; while (true) { var result = await output.ReadAsync(); if (result.IsCanceled) { break; } var buffer = result.Buffer; var end = buffer.End; var isCompleted = result.IsCompleted; if (!buffer.IsEmpty) { _sender = _socketSenderPool.Rent(); await _sender.SendAsync(_socket, buffer); // We don't return to the pool if there was an exception, and // we keep the _sender assigned so that we can dispose it in StartAsync. _socketSenderPool.Return(_sender); _sender = null; } output.AdvanceTo(end); if (isCompleted) { break; } } }
private async Task DoSend() { Exception?shutdownReason = null; Exception?unexpectedError = null; try { while (true) { var result = await Output.ReadAsync(); if (result.IsCanceled) { break; } var buffer = result.Buffer; if (!buffer.IsEmpty) { _sender = _socketSenderPool.Rent(); await _sender.SendAsync(_socket, buffer); // We don't return to the pool if there was an exception, and // we keep the _sender assigned so that we can dispose it in StartAsync. _socketSenderPool.Return(_sender); _sender = null; } Output.AdvanceTo(buffer.End); if (result.IsCompleted) { break; } } } catch (SocketException ex) when(IsConnectionResetError(ex.SocketErrorCode)) { shutdownReason = new ConnectionResetException(ex.Message, ex); _trace.ConnectionReset(this); } catch (Exception ex) when((ex is SocketException socketEx && IsConnectionAbortError(socketEx.SocketErrorCode)) || ex is ObjectDisposedException) { // This should always be ignored since Shutdown() must have already been called by Abort(). shutdownReason = ex; } catch (Exception ex) { shutdownReason = ex; unexpectedError = ex; _trace.ConnectionError(this, unexpectedError); } finally { Shutdown(shutdownReason); // Complete the output after disposing the socket Output.Complete(unexpectedError); // Cancel any pending flushes so that the input loop is un-paused Input.CancelPendingFlush(); } }