使用 gRPC 和 Unix 域套接字进行进程间通信

注意

此版本不是本文的最新版本。 有关当前版本,请参阅本文.NET 9 版本。

警告

此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅此文的 .NET 8 版本

重要

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

有关当前版本,请参阅本文.NET 9 版本。

作者:James Newton-King

.NET 支持使用 gRPC (IPC) 进行进程间通信 (IPC)。 有关开始使用 gRPC 在进程之间进行通信的详细信息,请参阅使用 gRPC 进行进程间通信

Unix 域套接字 (UDS) 是一种广泛受支持的 IPC 传输技术,当客户端和服务器位于同一台计算机上时,它比 TCP 更有效。 本文讨论如何通过 UDS 配置 gRPC 通信。

先决条件

服务器配置

Unix 域套接字受 Kestrel 支持,后者在 Program.cs 中进行配置:

var socketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");

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

上面的示例:

客户端配置

GrpcChannel 支持通过自定义传输进行 gRPC 调用。 创建通道后,可以使用包含自定义 ConnectCallbackSocketsHttpHandler 来配置它。 回调允许客户端通过自定义传输建立连接,然后通过该传输发送 HTTP 请求。

注意

GrpcChannel 的某些连接功能(例如客户端负载均衡和通道状态)不能与 Unix 域套接字一起使用。

Unix 域套接字连接工厂示例:

public class UnixDomainSocketsConnectionFactory
{
    private readonly EndPoint endPoint;

    public UnixDomainSocketsConnectionFactory(EndPoint endPoint)
    {
        this.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(this.endPoint, cancellationToken).ConfigureAwait(false);
            return new NetworkStream(socket, true);
        }
        catch
        {
            socket.Dispose();
            throw;
        }
    }
}

使用自定义连接工厂创建通道:

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

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

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

使用上述代码创建的通道通过 Unix 域套接字发送 gRPC 调用。