diff --git a/src/GameFrameX.SuperSocket.Connection/PipeConnection.cs b/src/GameFrameX.SuperSocket.Connection/PipeConnection.cs index 7889bc930..7184c47b3 100644 --- a/src/GameFrameX.SuperSocket.Connection/PipeConnection.cs +++ b/src/GameFrameX.SuperSocket.Connection/PipeConnection.cs @@ -262,5 +262,13 @@ protected override bool IsIgnorableException(Exception e) /// A token to monitor for cancellation requests. /// The total number of bytes read. protected abstract ValueTask FillInputPipeWithDataAsync(Memory memory, CancellationToken cancellationToken); + + /// + /// Cancels the pending read on the output pipe reader so the send loop unblocks immediately when the connection is being closed. + /// + protected override void CancelOutputPendingRead() + { + this.Output.Reader.CancelPendingRead(); + } } } diff --git a/src/GameFrameX.SuperSocket.Connection/PipeConnectionBase.cs b/src/GameFrameX.SuperSocket.Connection/PipeConnectionBase.cs index cab023029..29b585a8d 100644 --- a/src/GameFrameX.SuperSocket.Connection/PipeConnectionBase.cs +++ b/src/GameFrameX.SuperSocket.Connection/PipeConnectionBase.cs @@ -192,6 +192,7 @@ protected async Task CancelAsync() _cts.Cancel(); await CompleteWriterAsync(OutputWriter, _isDetaching).ConfigureAwait(false); + CancelOutputPendingRead(); } /// @@ -579,6 +580,13 @@ protected virtual async ValueTask CompleteWriterAsync(PipeWriter writer, bool is await writer.CompleteAsync().ConfigureAwait(false); } + /// + /// Cancels the pending read on the output pipe reader so that the send loop () blocked on ReadAsync returns promptly during connection shutdown. + /// + protected virtual void CancelOutputPendingRead() + { + } + internal struct BufferFilterResult { public Exception Exception { get; set; }