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

作者: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 调用。