AspNetCore.Docs/aspnetcore/grpc/interprocess-uds.md

3.8 KiB

title author description monikerRange ms.author ms.date uid
Inter-process communication with gRPC and Unix domain sockets jamesnk Learn how to use gRPC for inter-process communication with Unix domain sockets. >= aspnetcore-5.0 jamesnk 01/18/2023 grpc/interprocess-uds

Inter-process communication with gRPC and Unix domain sockets

By James Newton-King

.NET supports inter-process communication (IPC) using gRPC. For more information about getting started with using gRPC to communicate between processes, see Inter-process communication with gRPC.

Unix domain sockets (UDS) is a widely supported IPC transport that's more efficient than TCP when the client and server are on the same machine. This article discusses how to configure gRPC communication over UDS.

Prerequisites

Server configuration

Unix domain sockets are supported by Kestrel, which is configured in 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;
    });
});

The preceding example:

Client configuration

GrpcChannel supports making gRPC calls over custom transports. When a channel is created, it can be configured with a xref:System.Net.Http.SocketsHttpHandler that has a custom xref:System.Net.Http.SocketsHttpHandler.ConnectCallback. The callback allows the client to make connections over custom transports and then send HTTP requests over that transport.

Unix domain sockets connection factory example:

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;
        }
    }
}

Using the custom connection factory to create a channel:

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
    });
}

Channels created using the preceding code send gRPC calls over Unix domain sockets.