.NET 支持使用 gRPC 的进程间通信(IPC)。 有关开始使用 gRPC 在进程之间通信的详细信息,请参阅 与 gRPC 的进程间通信。
命名管道 是一种 IPC 传输方式,支持 Windows 的所有版本。 命名管道与 Windows 安全性 集成良好,以控制客户端对管道的访问。 本文讨论如何通过命名管道配置 gRPC 通信。
先决条件
- .NET 8 或更高版本
- Windows操作系统
服务器配置
命名管道由配置Program.cs的Kestrel支持。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenNamedPipe("MyPipeName", listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
});
上面的示例:
- 在ConfigureKestrel中配置Kestrel的终结点。
- 调用
ListenNamedPipe以侦听具有指定名称的命名管道。 - 创建未配置为使用 HTTPS 的命名管道终结点。 有关启用 HTTPS 的信息,请参阅 Kestrel HTTPS 终结点配置。
为命名管道配置“PipeSecurity”
若要控制哪些用户或组可以连接,请使用该 NamedPipeTransportOptions 类。 这允许指定自定义 PipeSecurity 对象。
示例:
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;
});
});
});
上面的示例:
- 使用
UseNamedPipes来访问和配置 NamedPipeTransportOptions。 - 设置属性 PipeSecurity 以控制哪些用户或组可以连接到命名管道。
- 为
Users组授予读/写访问权限。 可以根据需要为方案添加其他安全规则。
自定义 Kestrel 命名管道终结点
Kestrel的命名管道支持启用高级自定义,允许你使用此选项为每个终结点配置不同的安全设置。 此方法非常适合多个命名管道终结点需要唯一访问控制的方案。 从 .NET 9 开始,可以自定义每个终结点的管道。
在某些情况下,一个需要两个具有不同访问安全性的管道终结点的Kestrel应用程序可以非常有用。
CreateNamedPipeServerStream 选项可用于使用自定义安全设置创建管道,具体取决于管道名称。
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);
};
});
客户端配置
GrpcChannel 支持通过自定义传输进行 gRPC 调用。 创建通道后,可以使用具有自定义SocketsHttpHandler的通道进行配置ConnectCallback。 回调允许客户端通过自定义传输建立连接,然后通过该传输发送 HTTP 请求。
注释
GrpcChannel 的某些连接功能(例如客户端负载均衡和通道状态)不能与命名管道一起使用。
命名管道连接工厂示例:
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;
}
}
}
使用自定义连接工厂创建通道:
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
});
}
使用上述代码创建的通道通过命名管道发送 gRPC 调用。