C# 通过.NET中的PipeReader读取SSL
目前,我有一个工作实现,它使用SSL流,封装在bufferedstream中,并使用字节数组对流进行读/写调用 我想让它更快,从一些阅读资料来看,它看起来像是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
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);
}
}