Communicatie tussen processen met gRPC en named pipes

Door James Newton-King

.NET ondersteunt communicatie tussen processen (IPC) met behulp van gRPC. Zie Interprocescommunicatie met gRPC voor meer informatie over het gebruik van gRPC om te communiceren tussen processen.

Named pipes is een IPC-transport dat wordt ondersteund in alle versies van Windows. Benoemde pijpen kunnen goed worden geïntegreerd met Windows-beveiliging om clienttoegang tot de pijp te beheren. In dit artikel wordt beschreven hoe u gRPC-communicatie configureert via benoemde pijpen.

Vereiste voorwaarden

  • .NET 8 of hoger
  • Windows

Serverconfiguratie

Benoemde pijpen worden ondersteund door Kestrel, die is geconfigureerd in Program.cs:

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

Het voorgaande voorbeeld:

  • Hiermee configureert u de eindpunten van Kestrelin ConfigureKestrel.
  • Oproepen ListenNamedPipe om naar een benoemde pijp met de opgegeven naam te luisteren.
  • Hiermee maakt u een benoemd pipe-eindpunt dat niet is geconfigureerd voor het gebruik van HTTPS. Zie Kestrel HTTPS-eindpuntconfiguratievoor meer informatie over het inschakelen van HTTPS.

PipeSecurity configureren voor Named Pipes

Gebruik de NamedPipeTransportOptions klasse om te bepalen welke gebruikers of groepen verbinding kunnen maken. Hiermee kan een aangepast PipeSecurity object worden opgegeven.

Voorbeeld:

using Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes;
using System.IO.Pipes;
using System.Security.AccessControl;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.ListenNamedPipe("MyPipeName", listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http2;

        // Configure PipeSecurity
        listenOptions.UseNamedPipes(options =>
        {
            var pipeSecurity = new PipeSecurity();
            // Grant read/write access to the Users group
            pipeSecurity.AddAccessRule(new PipeAccessRule(
                "Users",
                PipeAccessRights.ReadWrite,
                AccessControlType.Allow));
            // Add additional rules as needed

            options.PipeSecurity = pipeSecurity;
        });
    });
});

Het voorgaande voorbeeld:

  • Hiermee UseNamedPipes kunt u toegang krijgen tot en configureren NamedPipeTransportOptions.
  • Hiermee stelt u de PipeSecurity eigenschap in om te bepalen welke gebruikers of groepen verbinding kunnen maken met de benoemde pijp.
  • Verleent lees-/schrijftoegang tot de Users groep. Aanvullende beveiligingsregels kunnen indien nodig worden toegevoegd voor het scenario.

Kestrel genaamde pijp-eindpunten aanpassen

KestrelDe ondersteuning voor benoemde pijpen maakt geavanceerde aanpassingen mogelijk, zodat u verschillende beveiligingsinstellingen voor elk eindpunt kunt configureren met behulp van de CreateNamedPipeServerStream optie. Deze benadering is ideaal voor scenario's waarbij meerdere benoemde pijpeindpunten unieke toegangsbeheer vereisen. De mogelijkheid om pijpen per eindpunt aan te passen is beschikbaar vanaf .NET 9.

Een voorbeeld van waar dit handig is, is een Kestrel app waarvoor twee pijpeindpunten met verschillende toegangsbeveiliging zijn vereist. De optie CreateNamedPipeServerStream kan worden gebruikt voor het maken van pijpen met aangepaste beveiligingsinstellingen, afhankelijk van de naam van de pijp.


var builder = WebApplication.CreateBuilder();
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenNamedPipe("pipe1");
    options.ListenNamedPipe("pipe2");
});

builder.WebHost.UseNamedPipes(options =>
{
    options.CreateNamedPipeServerStream = (context) =>
    {
        var pipeSecurity = CreatePipeSecurity(context.NamedPipeEndpoint.PipeName);

        return NamedPipeServerStreamAcl.Create(context.NamedPipeEndpoint.PipeName, PipeDirection.InOut,
            NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte,
            context.PipeOptions, inBufferSize: 0, outBufferSize: 0, pipeSecurity);
    };
});

Clientconfiguratie

GrpcChannel ondersteunt het maken van gRPC-aanroepen via op maat gemaakte transporten. Wanneer een kanaal wordt aangemaakt, kan het worden geconfigureerd met een SocketsHttpHandler en een aangepaste ConnectCallback. Met de callback kan de client verbindingen maken via aangepaste transporten en vervolgens HTTP-aanvragen verzenden via dat transport.

Opmerking

Sommige connectiviteitsfuncties, GrpcChannelzoals taakverdeling aan de clientzijde en kanaalstatus, kunnen niet samen met benoemde pijpen worden gebruikt.

Voorbeeld van benoemde pijpverbindingsfactory:

public class NamedPipesConnectionFactory
{
    private readonly string pipeName;

    public NamedPipesConnectionFactory(string pipeName)
    {
        this.pipeName = pipeName;
    }

    public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _,
        CancellationToken cancellationToken = default)
    {
        var clientStream = new NamedPipeClientStream(
            serverName: ".",
            pipeName: this.pipeName,
            direction: PipeDirection.InOut,
            options: PipeOptions.WriteThrough | PipeOptions.Asynchronous,
            impersonationLevel: TokenImpersonationLevel.Anonymous);

        try
        {
            await clientStream.ConnectAsync(cancellationToken).ConfigureAwait(false);
            return clientStream;
        }
        catch
        {
            clientStream.Dispose();
            throw;
        }
    }
}

Gebruik de aangepaste verbindingsfabriek om een kanaal te creëren.

public static GrpcChannel CreateChannel()
{
    var connectionFactory = new NamedPipesConnectionFactory("MyPipeName");
    var socketsHttpHandler = new SocketsHttpHandler
    {
        ConnectCallback = connectionFactory.ConnectAsync
    };

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

Kanalen die zijn gemaakt met behulp van de voorgaande code verzenden gRPC-aanroepen via benoemde pijpen.