通过.NET中的PipeReader读取SSL

use*_*708 12 .net c# io .net-core asp.net-core

目前,我通过使用SSL流(包装在缓冲流中)并仅使用字节数组在流上调用读/写来实现有效的实现。

我想使其更快,并且从一些阅读看来,这System.IO.Pipelines是高性能IO的必经之路。

我读过的很多文章/演示仅直接使用套接字演示了代码-自从我使用SSL以来,这似乎对我不起作用。

我找到了一些扩展来从流中获取管道读取器/写入器> Stream.UsePipeReader()Stream.UsePipeWriter()因此我尝试调用 SSLStream.UsePipeReader()

但是我总是得到错误:

System.NotSupportedException :  The ReadAsync method cannot be called when another read operation is pending.
   at System.Net.Security.SslStreamInternal.ReadAsyncInternal[TReadAdapter](TReadAdapter adapter, Memory`1 buffer)
   at Nerdbank.Streams.PipeExtensions.<>c__DisplayClass5_0.<<UsePipeReader>b__1>d.MoveNext() in D:\a\1\s\src\Nerdbank.Streams\PipeExtensions.cs:line 92
--- End of stack trace from previous location where exception was thrown ---
   at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()
   at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
   at System.IO.Pipelines.Pipe.GetReadAsyncResult()
Run Code Online (Sandbox Code Playgroud)

我从管道读取的代码是:

private async Task<string> ReadAsync(PipeReader reader)
        {

            var stringBuilder = new StringBuilder();

            while (true)
            {
                var result = await reader.ReadAsync();

                var buffer = result.Buffer;
                SequencePosition? position;

                do
                {
                    // Look for a EOL in the buffer
                    position = buffer.PositionOf((byte) '\n');

                    if (position != null)
                    {
                        // Process the line
                        ProcessLine(buffer.Slice(0, position.Value), stringBuilder);
                        buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
                    }
                } while (position != null);

                reader.AdvanceTo(buffer.Start, buffer.End);

                if (result.IsCompleted)
                {
                    reader.Complete();
                    break;
                }
            }

            return stringBuilder.ToString();
        }
Run Code Online (Sandbox Code Playgroud)

它没有被其他任何线程调用,因为我已经对其进行了锁定测试。为了测试目的,我一次只打一个电话。

谁能告诉我我在做什么错?

谢谢!

Bar*_*r J 3

我相信我可能知道答案。

您的问题可能出在这一行:

var result = await reader.ReadAsync();
Run Code Online (Sandbox Code Playgroud)

ReadAsync()您会看到,await 仅在 Send 方法中阻止执行,但与此同时,即使尚未完成,调用方中的代码也会继续执行。

现在,如果在完成之前再次调用 Send 方法,ReadAsync()您将收到您发布的异常,因为 SslStream 不允许多个读/写操作,并且您发布的代码不会阻止这种情况发生。

您需要针对这种情况编写自己的安全失败机制,以避免在第一个调用完成之前进行第二个调用。

由于您在这里使用循环:

while (true)
{
  //rest of code...
}
Run Code Online (Sandbox Code Playgroud)

我相信这就是您应该解决问题的地方。您正在进行第二次迭代,而第一次迭代尚未完成,从而导致:

System.NotSupportedException