Взаимодействие между процессами с сокетами домена gRPC и Unix

Автор: Джеймс Ньютон-Кинг (James Newton-King)

.NET поддерживает взаимодействие между процессами (IPC) с помощью gRPC. Дополнительные сведения о начале работы с использованием gRPC для обмена данными между процессами см. в разделе "Взаимодействие между процессами" с gRPC.

Сокеты домена Unix (UDS) — это широко поддерживаемый транспорт IPC, который эффективнее, чем TCP, когда клиент и сервер находятся на одном компьютере. В этой статье описывается настройка обмена данными gRPC по UDS.

Необходимые компоненты

Конфигурация сервера

Сокеты домена Unix поддерживаются KestrelProgram.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;
    });
});

Предшествующий пример:

  • Настраивает конечные точки Kestrel в ConfigureKestrel.
  • Вызывает ListenUnixSocket для прослушивания UDS по указанному пути.
  • Создает конечную точку UDS, которая не настроена для использования HTTPS. Дополнительные сведения о включении HTTPS см. в разделе о настройке конечной точки HTTPS Kestrel.

Настройка клиента

GrpcChannel поддерживает выполнение вызовов gRPC через настраиваемый транспорт. При создании канала его можно настроить с помощью SocketsHttpHandler, у которого имеется настраиваемый ConnectCallback. Обратный вызов позволяет клиенту устанавливать соединения через настраиваемые транспорты, а затем передавать 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
    });
}

Каналы, созданные с помощью приведенного выше кода, отправляют вызовы gRPC через сокеты доменов UNIX.