我正在尝试在.NET中创建客户端库。
目前,我通过使用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()
我要从管道读取的代码是:
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();
}
它没有被其他任何线程调用,因为我已经对其进行了锁定测试。为了测试目的,我一次只打一个电话。
有人可以告诉我我在做什么错吗?
谢谢!
答案 0 :(得分:0)
我相信我可能知道答案。
您的问题可能在此行:
var result = await reader.ReadAsync();
您看到的是,等待仅在Send方法中阻止执行,但是与此同时,即使ReadAsync()
尚未完成,调用方中的代码仍继续执行。
现在,如果在ReadAsync()
完成之前再次调用Send方法,则将收到已发布的异常,因为SslStream不允许进行多个读/写操作,并且已发布的代码也不会阻止这种情况从发生。
在这种情况下,您需要编写自己的安全失败机制,以避免在完成第一个调用之前进行第二个调用。
由于您在此处使用循环:
while (true)
{
//rest of code...
}
我相信这是您应该解决问题的地方。 您正在到达第二个迭代而第一个尚未完成,因此导致:
System.NotSupportedException
答案 1 :(得分:0)
您不能在另一个readasync中执行readasync,我认为您从pipereader派生的方法名称已更改为其他名称。
private async Task<string> **ReadAsync**(PipeReader reader)
{
var stringBuilder = new StringBuilder();
while (true)
{
var result = await reader.**ReadAsync**();
尝试这样修改。
**
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);
}
}
**
您仍然可以通过任何方式进行内存流传输。