首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有System.IO.Pipelines的TLS/SSL

带有System.IO.Pipelines的TLS/SSL
EN

Stack Overflow用户
提问于 2018-12-12 21:13:25
回答 1查看 2.7K关注 0票数 13

我注意到了新的System.IO.Pipelines,并试图将现有的、基于流的代码移植到它。流的问题得到了很好的理解,但同时它也具有丰富的相关类的生态系统。

在这里提供的示例中,有一个小型的tcp回送服务器。https://blogs.msdn.microsoft.com/dotnet/2018/07/09/system-io-pipelines-high-performance-io-in-net/

代码的一个片段附在这里:

代码语言:javascript
复制
    private static async Task ProcessLinesAsync(Socket socket)
    {
        Console.WriteLine($"[{socket.RemoteEndPoint}]: connected");

        var pipe = new Pipe();
        Task writing = FillPipeAsync(socket, pipe.Writer);
        Task reading = ReadPipeAsync(socket, pipe.Reader);

        await Task.WhenAll(reading, writing);

        Console.WriteLine($"[{socket.RemoteEndPoint}]: disconnected");
    }

    private static async Task FillPipeAsync(Socket socket, PipeWriter writer)
    {
        const int minimumBufferSize = 512;

        while (true)
        {
            try
            {
                // Request a minimum of 512 bytes from the PipeWriter
                Memory<byte> memory = writer.GetMemory(minimumBufferSize);

                int bytesRead = await socket.ReceiveAsync(memory, SocketFlags.None);
                if (bytesRead == 0)
                {
                    break;
                }

                // Tell the PipeWriter how much was read
                writer.Advance(bytesRead);
            }
            catch
            {
                break;
            }

            // Make the data available to the PipeReader
            FlushResult result = await writer.FlushAsync();

            if (result.IsCompleted)
            {
                break;
            }
        }

        // Signal to the reader that we're done writing
        writer.Complete();
    }

    private static async Task ReadPipeAsync(Socket socket, PipeReader reader)
    {
        while (true)
        {
            ReadResult result = await reader.ReadAsync();

            ReadOnlySequence<byte> buffer = result.Buffer;
            SequencePosition? position = null;

            do
            {
                // Find the EOL
                position = buffer.PositionOf((byte)'\n');

                if (position != null)
                {
                    var line = buffer.Slice(0, position.Value);
                    ProcessLine(socket, line);

                    // This is equivalent to position + 1
                    var next = buffer.GetPosition(1, position.Value);

                    // Skip what we've already processed including \n
                    buffer = buffer.Slice(next);
                }
            }
            while (position != null);

            // We sliced the buffer until no more data could be processed
            // Tell the PipeReader how much we consumed and how much we left to process
            reader.AdvanceTo(buffer.Start, buffer.End);

            if (result.IsCompleted)
            {
                break;
            }
        }

        reader.Complete();
    }

    private static void ProcessLine(Socket socket, in ReadOnlySequence<byte> buffer)
    {
        if (_echo)
        {
            Console.Write($"[{socket.RemoteEndPoint}]: ");
            foreach (var segment in buffer)
            {
                Console.Write(Encoding.UTF8.GetString(segment.Span));
            }
            Console.WriteLine();
        }
    }

当使用流时,您可以轻松地将SSL/TLS添加到代码中,只需将其包装在SslStream中即可。如何用管道来解决这个问题?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-12-20 17:06:35

命名管道是一个网络协议,就像HTTP、FTP和SMTP一样。让我们看看.net框架中的一些快速示例:

  • HTTP连接会自动利用SSL,这取决于基本URI。如果URI存在"HTTPS:",则使用SSL。
  • 通过在调用EnableSsl ()之前将GetResponse属性设置为true,FTP连接利用了SSL。
  • SMTP以与FTP相同的方式利用SSL。

但是,如果我们使用的是不同的网络协议,比如管道呢?从一开始,我们就知道没有类似于"HTTPS“前缀的东西。此外,我们可以阅读System.IO.Piplines的文档,并看到没有"EnableSsl“方法。但是,在.NET框架和.NET核心中,SslStream类都是可用的。这个类允许您从几乎所有可用的流中构建SslStream。

.NET框架和.NET核心中也有System.IO.Pipes名称空间。管道命名空间中可用的类非常有用。

  • AnonymousPipeClientStream
  • AnonymousPipeServerStream
  • NamedPipeClientStream
  • NamedPipeServerStream
  • PipeStream

所有这些类都返回继承自Stream的某种对象,因此可以在SslStream的构造函数中使用。

这与System.IO.Piplines名称空间的关系如何?好吧..。没有。在System.IO.Pipelines命名空间中定义的类、结构或接口没有一个继承自流。因此我们不能直接使用SslStream类。

相反,我们可以访问PipeReaders和PipeWriters。有时,我们只有其中一个可用,但让我们考虑一个双向管道,以便我们可以同时访问这两个。

System.IO.Piplines命名空间有益地提供了一个IDuplexPipe接口。如果我们想将PipeReader和PipeWriters封装在SSL流中,我们需要定义一个实现IDuplexPipe的新类型。

在这种新型中:

  • 我们将定义一个SslStream。
  • 我们将使用通用管道作为输入和输出缓冲区。
  • PipeReader将使用输入缓冲区的读取器。我们将使用这个输入缓冲区从SSL流中获取数据。
  • PipeWriter将使用输出缓冲区的写入器。我们将使用此输出缓冲区向SSL流发送数据。

下面是伪代码中的一个示例:

代码语言:javascript
复制
SslStreamDuplexPipe : IDuplexPipe
{ 
    SslStream sslStream;
    Pipe inputBuffer;
    Pipe outputBuffer;

    public PipeReader Input = inputBuffer.Reader;
    public PipeWriter Output = outputBuffer.Writer;

    ReadDataFromSslStream()
    {
        int bytes = sslStream.Read(new byte[2048], 0, 2048);
        inputBuffer.Writer.Advance(bytes)
        inputBuffer.Writer.Flush();
    }

    //and the reverse to write to the SslStream 
 }

正如您所看到的,我们仍然在使用来自System.Net.Security命名空间的System.Net.Security类,它只需要再走几步。

这是否意味着您基本上仍在使用流?是啊!但是,一旦完全实现了SslStreamDuplexPipe类,就只能使用管道了。不需要将SslStream封装在所有东西上。

马克·格雷维尔( Marc )对此作了更多、更详细的解释。这三部分中的第一部分可以在这里找到:https://blog.marcgravell.com/2018/07/pipe-dreams-part-1.html

此外,您还可以阅读提到的各种.NET类:

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53751435

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档