共用方式為


與 gRPC 和命名管道的跨進程通訊

作者:James Newton-King

.NET 支援使用 gRPC 進行進程間通訊 (IPC)。 如需開始使用 gRPC 在進程之間通訊的詳細資訊,請參閱 與 gRPC 之間的進程間通訊

命名管道 是所有 Windows 版本支援的 IPC 傳輸。 命名管道與 Windows 安全性 整合,以控制管道的用戶端存取。 本文討論如何透過命名管道設定 gRPC 通訊。

先決條件

  • .NET 8 或更新版本
  • 窗戶

伺服器組態

命名管道支援 Kestrel,其設定於 中 Program.cs

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.ListenNamedPipe("MyPipeName", listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http2;
    });
});

上述範例:

  • 在 Kestrel 中設定 ConfigureKestrel 的端點。
  • 呼叫 ListenNamedPipe 以接聽具有指定名稱的命名管道。
  • 建立未設定為使用 HTTPS 的命名管道端點。 如需啟用 HTTPS 的詳細資訊,請參閱 Kestrel HTTPS 端點組態

設定命名管道的 PipeSecurity

若要控制哪些使用者或群組可以連線,請使用 類別 NamedPipeTransportOptions 。 這可讓指定自定義 PipeSecurity 物件。

範例:

using Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes;
using System.IO.Pipes;
using System.Security.AccessControl;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.ListenNamedPipe("MyPipeName", listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http2;

        // Configure PipeSecurity
        listenOptions.UseNamedPipes(options =>
        {
            var pipeSecurity = new PipeSecurity();
            // Grant read/write access to the Users group
            pipeSecurity.AddAccessRule(new PipeAccessRule(
                "Users",
                PipeAccessRights.ReadWrite,
                AccessControlType.Allow));
            // Add additional rules as needed

            options.PipeSecurity = pipeSecurity;
        });
    });
});

上述範例:

  • 使用 UseNamedPipes 來存取與設定 NamedPipeTransportOptions
  • 設定 PipeSecurity 屬性,以控制哪些使用者或群組可以連接到命名管道。
  • 授與群組的 Users 讀取/寫入存取權。 您可以視需要為案例新增其他安全性規則。

自訂 Kestrel 具名管道端點

Kestrel的命名管道支援可啟用進階自定義,讓您使用 CreateNamedPipeServerStream 選項為每個端點設定不同的安全性設定。 這種方法很適合多個具名管道端點需要唯一訪問控制的案例。 從 .NET 9 開始,即可自定義每個端點的管道。

其中,這很有用的範例是需要兩個 Kestrel 管道端點且具有不同存取安全性的應用程式。 CreateNamedPipeServerStream 選項可用來根據管道名稱建立具有自訂安全性設定的管道。


var builder = WebApplication.CreateBuilder();
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenNamedPipe("pipe1");
    options.ListenNamedPipe("pipe2");
});

builder.WebHost.UseNamedPipes(options =>
{
    options.CreateNamedPipeServerStream = (context) =>
    {
        var pipeSecurity = CreatePipeSecurity(context.NamedPipeEndpoint.PipeName);

        return NamedPipeServerStreamAcl.Create(context.NamedPipeEndpoint.PipeName, PipeDirection.InOut,
            NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte,
            context.PipeOptions, inBufferSize: 0, outBufferSize: 0, pipeSecurity);
    };
});

客戶端設定

GrpcChannel 支援透過自訂傳輸進行 gRPC 呼叫。 建立通道後,可以使用具有自訂 SocketsHttpHandlerConnectCallback 加以設定。 回呼可讓用戶端透過自訂傳輸進行連線,然後透過該傳輸傳送 HTTP 要求。

備註

的某些 GrpcChannel連線功能,例如用戶端負載平衡和通道狀態,無法與命名管道一起使用。

命名管道連線處理站範例:

public class NamedPipesConnectionFactory
{
    private readonly string pipeName;

    public NamedPipesConnectionFactory(string pipeName)
    {
        this.pipeName = pipeName;
    }

    public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _,
        CancellationToken cancellationToken = default)
    {
        var clientStream = new NamedPipeClientStream(
            serverName: ".",
            pipeName: this.pipeName,
            direction: PipeDirection.InOut,
            options: PipeOptions.WriteThrough | PipeOptions.Asynchronous,
            impersonationLevel: TokenImpersonationLevel.Anonymous);

        try
        {
            await clientStream.ConnectAsync(cancellationToken).ConfigureAwait(false);
            return clientStream;
        }
        catch
        {
            clientStream.Dispose();
            throw;
        }
    }
}

使用自訂連線 Factory 建立通道:

public static GrpcChannel CreateChannel()
{
    var connectionFactory = new NamedPipesConnectionFactory("MyPipeName");
    var socketsHttpHandler = new SocketsHttpHandler
    {
        ConnectCallback = connectionFactory.ConnectAsync
    };

    return GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions
    {
        HttpHandler = socketsHttpHandler
    });
}

使用上述程式代碼建立的通道會透過命名管道傳送 gRPC 呼叫。