Net Core gRPC - 08. 客户端工厂集成与进程间通信
Net Core gRPC 系列
1. 什么是客户端工厂集成
gRPC 与 HttpClientFactory 的集成提供了一种创建 gRPC 客户端的集中方式。 它可用作配置独立 gRPC 客户端实例的替代方法。 Grpc.Net.ClientFactory NuGet 包中提供了工厂集成。
工厂具有以下优势:
提供了用于配置逻辑 gRPC 客户端实例的中心位置
可管理基础 HttpClientMessageHandler 的生存期
在 ASP.NET Core gRPC 服务中自动传播截止时间和取消
1 2 3 4
| services.AddGrpcClient<Greeter.GreeterClient>(o => { o.Address = new Uri("https://localhost:5001"); });
|
2. 进程间通信
不同计算机上的客户端和服务器之间的 gRPC 调用通常通过 TCP 套接字发送。 TCP 是跨网络或 Internet 进行通信的绝佳选择。 但是,当客户端和服务器位于同一台计算机上时,IPC 传输可以提供性能优势,更好地与 OS 功能集成。
.NET 支持多个 IPC 传输:
Unix 域套接字 (UDS) 是一种广泛受支持的 IPC 技术。 UDS 是生成跨平台应用的最佳选择,可在 Linux、macOS 和 Windows 10/Windows Server 2019 或更高版本上使用。
所有版本的 Windows 都支持命名管道。 命名管道与 Windows 安全性良好集成,可用于控制客户端对管道的访问。
通过在应用启动时实现 IConnectionListenerFactory 和注册实现进行的其他 IPC 传输。
❗ 备注
ASP.NET Core 中对命名管道的内置支持需要 .NET 8 或更高版本。 .NET 8 目前为预览版,将于 2023 年底发布。
Unix进程间通信1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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; } } }
|
windows 进程间通信1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
public class NamedPipesConnectionFactory { private readonly string _pipeName;
public NamedPipesConnectionFactory(string pipeName) { _pipeName = pipeName; }
public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _, CancellationToken cancellationToken = default) { var clientStream = new NamedPipeClientStream( serverName: ".", pipeName: _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; } } }
|
3. 使用策略模式创建Grpc channel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| public interface IColaGrpc { GrpcChannel CreateChannel(string grpcUrl, string? pipeNameOrSocketPath=null); }
public class ColaWindowsGrpc : IColaGrpc { public GrpcChannel CreateChannel(string grpcUrl, string? pipeNameOrSocketPath=null) { if (SystemHelper.NetCoreVersion!.Major > 8) { var connectionFactory = new NamedPipesConnectionFactory(pipeNameOrSocketPath!); var socketsHttpHandler = new SocketsHttpHandler { ConnectCallback = connectionFactory.ConnectAsync }; return GrpcChannel.ForAddress(grpcUrl, new GrpcChannelOptions { HttpHandler = socketsHttpHandler }); } return GrpcChannel.ForAddress(grpcUrl); } } public class ColaUnixGrpc : IColaGrpc { public GrpcChannel CreateChannel(string grpcUrl, string? pipeNameOrSocketPath=null) { var udsEndPoint = new UnixDomainSocketEndPoint(pipeNameOrSocketPath!); var connectionFactory = new UnixDomainSocketsConnectionFactory(udsEndPoint); var socketsHttpHandler = new SocketsHttpHandler { ConnectCallback = connectionFactory.ConnectAsync }; return GrpcChannel.ForAddress(grpcUrl, new GrpcChannelOptions { HttpHandler = socketsHttpHandler }); } } public class ColaGrpcHelper { private readonly IColaGrpc _colaGrpc; public ColaGrpcHelper(IColaGrpc colaGrpc) { _colaGrpc = colaGrpc; } public GrpcChannel CreateChannel(string grpcUrl, string? pipeNameOrSocketPath=null) { return _colaGrpc.CreateChannel(grpcUrl, pipeNameOrSocketPath); } }
|
创建channel
1
| var channel = new ColaGrpcHelper(new ColaWindowsGrpc()).CreateChannel("https://localhost:5005");
|
完整代码可以在 GitHub
WebApplication1Test 整合了gRPC,ConsoleApp1Test有具体调用示例