C# 通过.NET中的PipeReader读取SSL

C# 通过.NET中的PipeReader读取SSL,c#,.net,asp.net-core,.net-core,io,C#,.net,Asp.net Core,.net Core,Io,目前,我有一个工作实现,它使用SSL流,封装在bufferedstream中,并使用字节数组对流进行读/写调用 我想让它更快,从一些阅读资料来看,它看起来像是System.IO.pipeline是实现高性能IO的途径 我读过的很多文章/演示都直接演示了使用套接字的代码——因为我使用的是SSL,所以这似乎不适用于我 我找到了一些扩展来从流>stream.UsePipeReader()或stream.UsePipeWriter()获取管道读取器/写入器,因此我尝试调用 SSLStream.UsePi

目前,我有一个工作实现,它使用SSL流,封装在bufferedstream中,并使用字节数组对流进行读/写调用

我想让它更快,从一些阅读资料来看,它看起来像是
System.IO.pipeline
是实现高性能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()
System.NotSupportedException:当另一个读取操作挂起时,无法调用ReadAsync方法。
位于System.Net.Security.SslStreamInternal.ReadAsyncInternal[TReadAdapter](TReadAdapter适配器,内存`1缓冲区)
在d:\a\1\s\src\Nerdbank.Streams\PipeExtensions.c\uuu中显示Class5\u 0.d.MoveNext(),第92行
---来自引发异常的上一个位置的堆栈结束跟踪---
在System.IO.Pipelines.PipeCompletion.ThrowLatchedException()中
at System.IO.Pipelines.Pipe.GetReadResult(ReadResult&result)
在System.IO.Pipelines.Pipe.GetReadAsyncResult()中
从管道中读取的代码是:

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();
        }
专用异步任务ReadAsync(PipeReader)
{
var stringBuilder=新的stringBuilder();
while(true)
{
var result=await reader.ReadAsync();
var buffer=result.buffer;
顺序位置?位置;
做
{
//在缓冲区中查找下线
position=buffer.PositionOf((字节)'\n');
如果(位置!=null)
{
//处理生产线
ProcessLine(buffer.Slice(0,position.Value),stringBuilder);
buffer=buffer.Slice(buffer.GetPosition(1,position.Value));
}
}while(位置!=null);
reader.AdvanceTo(buffer.Start、buffer.End);
如果(结果已完成)
{
reader.Complete();
打破
}
}
返回stringBuilder.ToString();
}
它没有被任何其他线程调用,因为我已经用锁对它进行了测试。为了测试的目的,我一次只打一个电话

谁能告诉我我做错了什么


谢谢

我相信我可能知道答案

您的问题可能在以下方面:

var result = await reader.ReadAsync();
您可以看到,wait仅在Send方法中阻止执行,但同时调用方中的代码继续执行,即使
ReadAsync()
尚未完成

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

您需要为这种情况编写自己的安全故障机制,以避免在第一次调用完成之前进行第二次调用

因为您在这里使用的是循环:

while (true)
{
  //rest of code...
}
我相信这是你应该解决问题的地方。 您正在进行第二次迭代,而第一次迭代尚未完成,因此导致:


System.NotSupportedException

您不能在另一个readasync中执行readasync,我认为您从pipereader派生的方法已经将方法名称更改为其他名称

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

            var stringBuilder = new StringBuilder();

            while (true)
            {
                var result = await reader.**ReadAsync**();
专用异步任务**ReadAsync**(PipeReader)
{
var stringBuilder=新的stringBuilder();
while(true)
{
var result=wait reader.**ReadAsync**();
尝试这样修改

**

async ValueTask ReadSomeDataAsync(PipeReader)
{
while(true)
{
//等待一些可用的数据
ReadResult read=wait reader.ReadAsync();
ReadOnlySequence buffer=read.buffer;
//检查我们是否已经到达终点
//处理一切
if(buffer.IsEmpty&&read.IsCompleted)
break;//退出循环
//处理我们收到的东西
foreach(缓冲区中的内存段)
{
字符串s=Encoding.ASCII.GetString(
段(跨度);
控制台。写入;
}
//告诉烟斗我们什么都用过了
reader.AdvanceTo(buffer.End);
}
}
**


无论如何,您仍然可以使用内存流。

我认为首先在您的代码中应该是
\n
,而不是
\r
all@TarunLalwani谢谢-我已经尝试了
\n
\r
(我看到了使用它们的不同演示)但两者都给出了相同的例外情况,那么看看这是否有任何帮助,你的意思是什么,你已经使用
lock
对它进行了测试?你不能在
lock
中使用
wait
。你确定你的
ReadAsync
方法中没有
wait
async ValueTask ReadSomeDataAsync(PipeReader reader)
{
    while (true)
    {
        // await some data being available
        ReadResult read = await reader.ReadAsync();
        ReadOnlySequence<byte> buffer = read.Buffer;
        // check whether we've reached the end
        // and processed everything
        if (buffer.IsEmpty && read.IsCompleted)
            break; // exit loop
        // process what we received
        foreach (Memory<byte> segment in buffer)
        {
            string s = Encoding.ASCII.GetString(
                segment.Span);
            Console.Write(s);
        }
        // tell the pipe that we used everything
        reader.AdvanceTo(buffer.End);
    }
}