Client主文件:
static void Main(string[] args) { var serverAddress = "https://localhost:5001"; using var channel = GrpcChannel.ForAddress(serverAddress); var client = new Greeter.GreeterClient(channel); var reply = client.SayHello(new HelloRequest { Name = "宋小宝!" }); Console.WriteLine(reply.Message.ToString()); Console.WriteLine("Press any key to exit..."); Console.ReadKey(); }使用服务器地址创建GrpcChannel,然后使用GrpcChannel对象实例化GreeterClient;然后使用SayHello同步方法; 服务器响应时,打印结果。
脚手架例子就可以入门,下面聊一聊另外的核心功能
3. 其他核心功能 1. 通信方式Unary RPC(一元Rpc调用): 上面的例子
Server streaming RPC : 服务器流式RPC,客户端在其中向服务器发送请求,并获取流以读取回一系列消息。客户端从返回的流中读取,直到没有更多消息为止。 gRPC保证单个RPC调用中的消息顺序。
Client streaming RPC:客户端流式RPC,客户端在其中编写一系列消息,然后再次使用提供的流将它们发送到服务器。客户端写完消息后,它将等待服务器读取消息并返回响应。同样,gRPC保证了单个RPC调用中的消息顺序
Bidirectional streaming RPC: 双向流式RPC,双方都使用读写流发送一系列消息。这两个流是独立运行的,因此客户端和服务器可以按照自己喜欢的顺序进行读写:例如,服务器可以在写响应之前等待接收所有客户端消息,或者可以先读取一条消息再写入一条消息,或读写的其他组合。每个流中的消息顺序都会保留。
2. Metadata元数据是以键值对列表的形式提供的有关特定RPC调用的信息(例如身份验证详细信息),其中键是字符串,值通常是字符串,但可以是二进制数据。
元数据对于gRPC本身是不透明的:它允许客户端向服务器提供与调用相关的信息,反之亦然。
3. ChannelsgRPC通道提供到指定主机和端口上的gRPC服务器的连接。
创建客户端存根时用到它,可以指定通道参数来修改gRPC的默认行为,例如打开或关闭消息压缩。
通道具有状态,包括已连接和空闲。
针对脚手架项目,稍作修改--->乒乓球局
(考察gRpc双向流式通信、Timeout机制、异常处理):
客户端发送"gridsum", 服务端回发"musdirg"; 客户端再发送"gridsum", 往复......
① 添加接口
rpc PingPongHello(stream HelloRequest) returns (stream HelloReply);② 实现服务契约
public override async Task PingPongHello(IAsyncStreamReader<HelloRequest> requestStream,IServerStreamWriter<HelloReply> responseStream, ServerCallContext context) { try { while (!context.CancellationToken.IsCancellationRequested) { var asyncRequests = requestStream.ReadAllAsync(); // 客户端与服务端"打乒乓" await foreach (var req in asyncRequests) { var send = Reverse(req.Name); await responseStream.WriteAsync(new HelloReply { Message = send, Id = req.Id + 1 }); Debug.WriteLine($"第{req.Id}回合,服务端收到 {req.Name};开始第{req.Id + 1}回合,服务端回发 {send}"); } } } catch (RpcException ex) { System.Diagnostics.Debug.WriteLine($"{ex.Message}"); } catch (IOException ex) { System.Diagnostics.Debug.WriteLine($"{ex.Message}"); } }③ 添加客户端代码
using (var cancellationTokenSource = new CancellationTokenSource( 5* 1000)) { try { var duplexMessage = client.PingPongHello(null, null, cancellationTokenSource.Token); await duplexMessage.RequestStream.WriteAsync(new HelloRequest { Id = 1, Name = "gridsum" }) ; var asyncResp = duplexMessage.ResponseStream.ReadAllAsync(); await foreach (var resp in asyncResp) { var send = Reverse(resp.Message); await duplexMessage.RequestStream.WriteAsync(new HelloRequest {Id= resp.Id, Name = send }); Console.WriteLine($"第{resp.Id}回合,客户端收到 {resp.Message}, 客户端发送{send}"); } } catch (RpcException ex) { Console.WriteLine("打乒乓球时间到了(客户端5s后终断gRpc连接)"); } }https://github.com/zaozaoniao/GrpcAuthor
总结gRPC是具有可插拔身份验证和负载平衡功能的高性能RPC框架。
使用protocol buffers定义结构化数据;使用不同语言自动产生的源代码在各种数据流中写入和读取结构化数据。
在本文中,您学习了如何使用protocol buffers(版本3)定义服务接口以及如何使用C#实现服务。最后,您使用gRPC双向流式通信创建了 "打乒乓球"Demo。
Additional Resources