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; }