與 gRPC 的處理程序間通訊

在同一部電腦上執行的處理序可以設計成相互通訊。 作業系統提供技術以啟用快速且有效率的處理序間通訊 (IPC)。 IPC 技術的熱門範例包括 Unix 網域通訊端和具名管道。

.NET 支援使用 gRPC 進行處理序間通訊。

ASP.NET Core 中具名管道的內建支援需要 .NET 8 或更新版本。

開始使用

IPC 呼叫會從用戶端傳送至伺服器。 若要使用 gRPC 在電腦的應用程式之間進行通訊,至少一個應用程式必須裝載 ASP.NET Core gRPC 伺服器。

ASP.NET Core gRPC 伺服器通常是從 gRPC 範本建立。 範本建立的專案檔會使用 Microsoft.NET.SDK.Web 作為 SDK:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <ItemGroup>
    <PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
    <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
  </ItemGroup>

</Project>

Microsoft.NET.SDK.Web SDK 值會自動將參考新增至 ASP.NET Core 架構。 此參考可讓應用程式使用裝載伺服器所需的 ASP.NET Core 類型。

您也可以將伺服器新增至現有的非 ASP.NET Core 專案,例如 Windows 服務、WPF 應用程式或 WinForms 應用程式。 如需詳細資訊,請參閱 在非 ASP.NET Core 專案中裝載 gRPC

處理序間通訊 (IPC) 傳輸

不同電腦上用戶端和伺服器之間的 gRPC 呼叫通常會經由 TCP 通訊端傳送。 TCP 是跨網路或網際網路進行通訊的好選擇。 不過,在相同電腦的處理序之間進行通訊時,IPC 傳輸具有以下優點:

  • 額外負荷較少且傳送速度更快。
  • 與 OS 安全性功能整合。
  • 不使用 TCP 連接埠這些有限資源。

.NET 支援多個 IPC 傳輸:

視作業系統而定,跨平台應用程式可能會選擇不同的 IPC 傳輸。 應用程式可以在啟動時檢查作業系統,並選擇該平台所需的傳輸:

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    if (OperatingSystem.IsWindows())
    {
        serverOptions.ListenNamedPipe("MyPipeName");
    }
    else
    {
        var socketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");
        serverOptions.ListenUnixSocket(socketPath);
    }

    serverOptions.ConfigureEndpointDefaults(listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http2;
    });
});

安全性考量

IPC 應用程式會傳送和接收 RPC 呼叫。 外部通訊是 IPC 應用程式的潛在攻擊媒介,必須提供適當防護。

針對非預期的呼叫端保護 IPC 伺服器應用程式

IPC 伺服器應用程式裝載 RPC 服務,以供其他應用程式呼叫。 應該驗證傳入的呼叫端,以防止不受信任的用戶端對伺服器進行 RPC 呼叫。

傳輸安全性是保護伺服器的一種方式。 IPC 傳輸 (例如 Unix 網域通訊端和具名管道) 支援依作業系統權限來限制存取:

  • 具名管道支援使用 Windows 存取控制模型來保護管道。 伺服器開始使用 PipeSecurity 類別時,可以在 .NET 中設定存取權限。
  • Unix 網域通訊端支援使用檔案權限保護通訊端。

保護 IPC 伺服器的另一種方式是使用 ASP.NET Core 內建的驗證和授權機制。 例如,伺服器可以設定為需要憑證驗證。 用戶端應用程式在沒有所需憑證的情況下進行 RPC 呼叫會失敗,並獲得未經授權的回應。

驗證 IPC 用戶端應用程式中的伺服器

用戶端應用程式必須對其呼叫的伺服器驗證身分識別。 驗證是必要程序,藉此防止惡意執行者停止受信任的伺服器、執行自己的伺服器,以及接受用戶端傳入的資料。

具名管道支援取得伺服器執行時所用的帳戶。 用戶端可以驗證伺服器是否由預期帳戶啟動:

internal static bool CheckPipeConnectionOwnership(
    NamedPipeClientStream pipeStream, SecurityIdentifier expectedOwner)
{
    var remotePipeSecurity = pipeStream.GetAccessControl();
    var remoteOwner = remotePipeSecurity.GetOwner(typeof(SecurityIdentifier));
    return expectedOwner.Equals(remoteOwner);
}

驗證伺服器的另一個方法是在 ASP.NET Core 內使用 HTTPS 保護其端點。 用戶端可以設定 SocketsHttpHandler,驗證伺服器在建立連線時是否使用預期的憑證。

var socketsHttpHandler = new SocketsHttpHandler()
{
    SslOptions = new SslOptions()
    {
        RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
        {
            if (sslPolicyErrors != SslPolicyErrors.None)
            {
                return false;
            }

            // Validate server cert thumbprint matches the expected thumbprint.
        }
    }
};

防止具名管道權限提升

具名管道支援名為模擬的功能。 藉由模擬功能,具名管道伺服器可以使用用戶端使用者的權限來執行程式碼。 這是很強大的功能,但可讓低權限伺服器模擬高權限呼叫端,然後執行惡意程式碼。

為了防範此類攻擊,用戶端可在連線到伺服器時不允許模擬。 除非伺服器需要,否則在建立用戶端連線時應使用 NoneAnonymousTokenImpersonationLevel 值:

using var pipeClient = new NamedPipeClientStream(
    serverName: ".", pipeName: "testpipe", PipeDirection.In, PipeOptions.None, TokenImpersonationLevel.None);
await pipeClient.ConnectAsync();

TokenImpersonationLevel.None 是沒有 impersonationLevel 參數之 NamedPipeClientStream 建構函式中的預設值。

設定用戶端和伺服器

用戶端和伺服器必須設定為使用處理序間通訊 (IPC) 傳輸。 如需設定 Kestrel 和 SocketsHttpHandler 以使用 IPC 的詳細資訊,請參閱:

注意

ASP.NET Core 中具名管道的內建支援需要 .NET 8 或更新版本。

在同一部電腦上執行的處理序可以設計成相互通訊。 作業系統提供技術以啟用快速且有效率的處理序間通訊 (IPC)。 IPC 技術的熱門範例包括 Unix 網域通訊端和具名管道。

.NET 支援使用 gRPC 進行處理序間通訊。

注意

ASP.NET Core 中具名管道的內建支援需要 .NET 8 或更新版本。
如需詳細資訊,請參閱 本主題的 .NET 8 或更新版本

開始使用

gRPC 呼叫會從用戶端傳送至伺服器。 若要使用 gRPC 在電腦的應用程式之間進行通訊,至少一個應用程式必須裝載 ASP.NET Core gRPC 伺服器。

ASP.NET Core 和 gRPC 可以使用 .NET Core 3.1 或更新版本將架構新增 Microsoft.AspNetCore.App 至專案,裝載于任何應用程式中。

<Project Sdk="Microsoft.NET.Sdk">

  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
    <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
  </ItemGroup>

</Project>

上述專案檔:

  • 將架構參考新增至 Microsoft.AspNetCore.App。 架構參考可讓 non-ASP.NET Core 應用程式,例如 Windows 服務、WPF 應用程式或 WinForms 應用程式,使用 ASP.NET Core 並裝載 ASP.NET Core 伺服器。
  • 將 NuGet 套件參考新增至 Grpc.AspNetCore
  • 新增檔案 .proto

設定 Unix 網域通訊端

不同電腦上用戶端和伺服器之間的 gRPC 呼叫通常會經由 TCP 通訊端傳送。 TCP 是專為跨網路通訊而設計的。 Unix 網域通訊端 (UDS) 是廣受支援的 IPC 技術,在用戶端和伺服器位於同一部電腦上時,比 TCP 更有效率。 .NET 提供用戶端和伺服器應用程式中 UDS 的內建支援。

需求:

伺服器組態

支援 Unix 網域通訊端 (UDS), Kestrel 其設定于 中 Program.cs

public static readonly string SocketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
            webBuilder.ConfigureKestrel(options =>
            {
                if (File.Exists(SocketPath))
                {
                    File.Delete(SocketPath);
                }
                options.ListenUnixSocket(SocketPath, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                });
            });
        });

上述範例:

  • ConfigureKestrel 中設定 Kestrel 的端點。
  • 呼叫 ListenUnixSocket 以接聽具有指定路徑的 UDS。
  • 建立未設定為使用 HTTPS 的 UDS 端點。 如需啟用 HTTPS 的詳細資訊,請參閱 Kestrel HTTPS 端點組態

用戶端組態

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

Unix 網域通訊端連線 Factory 範例:

public class UnixDomainSocketConnectionFactory
{
    private readonly EndPoint _endPoint;

    public UnixDomainSocketConnectionFactory(EndPoint endPoint)
    {
        _endPoint = endPoint;
    }

    public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _,
        CancellationToken cancellationToken = default)
    {
        var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);

        try
        {
            await socket.ConnectAsync(_endPoint, cancellationToken).ConfigureAwait(false);
            return new NetworkStream(socket, true);
        }
        catch
        {
            socket.Dispose();
            throw;
        }
    }
}

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

public static readonly string SocketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");

public static GrpcChannel CreateChannel()
{
    var udsEndPoint = new UnixDomainSocketEndPoint(SocketPath);
    var connectionFactory = new UnixDomainSocketConnectionFactory(udsEndPoint);
    var socketsHttpHandler = new SocketsHttpHandler
    {
        ConnectCallback = connectionFactory.ConnectAsync
    };

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

使用上述程式碼建立的通道會透過 Unix 網域通訊端傳送 gRPC 呼叫。 您可以使用 和 SocketsHttpHandler 中的 Kestrel 擴充性來實作其他 IPC 技術的支援。