gRPC(gRPC Remote Procedure Call)是由Google開發的高效能、跨語言的遠端過程呼叫框架。它基於HTTP/2協議進行通訊,支援多種程式語言,包括C++, C#, Java, Python等,使不同語言的應用程式可以透過遠端呼叫相互通訊。
1.關鍵特點和用途:
高效能:gRPC採用了HTTP/2協議,具有低延遲、高吞吐量和複用連線的特點。這使得它非常適合於需要高效能通訊的應用程式。
跨語言支援:gRPC支援多種程式語言,允許不同語言的應用程式之間進行跨語言通訊。這使得它在微服務架構中非常有用,因為不同的服務可以使用不同的程式語言實現。
IDL(Interface Definition Language):gRPC使用ProtoBuf(Protocol Buffers)作為IDL,允許您定義服務介面和訊息型別。這提供了強型別的通訊,使得通訊更加清晰和高效。
多種通訊型別:gRPC支援不同型別的通訊,包括請求-響應、伺服器流、客戶端流和雙向流。這允許您選擇最適合您應用程式需求的通訊方式。
自動化程式碼生成:透過ProtoBuf定義服務介面和訊息型別,gRPC工具會自動生成客戶端和伺服器端的程式碼,這樣可以大大減少開發工作量。
認證和安全:gRPC支援各種認證和安全機制,包括SSL/TLS,OAuth等,以確保通訊的安全性。
服務發現:gRPC可以與服務發現工具(如Consul、etcd)整合,從而實現動態服務發現和負載均衡。
可擴充套件性:gRPC是一個可擴充套件的框架,支援各種自定義擴充套件和中介軟體。
2.GRPC思路
Grpc類似於一種協議,遵循網路通訊,以.proto檔案為協議模板進行客戶端與服務端的互動開發,不限制客戶端和服務端的程式碼語言風格.也可以在服務端與客戶端使用不同的語言開發
3.編寫.proto檔案
// Protocol Buffers 語法版本 proto3 版本 syntax = "proto3"; // 定義了訊息型別和服務的包名,類似於名稱空間,用於避免命名衝突。 package Calculator; // 定義了一個 gRPC 服務。在大括號中,您可以列出服務方法的定義。 service CalculatorService { // 定義了一個服務方法。rpc 表示定義一個遠端過程呼叫(RPC)方法。MyMethod 是方法的名稱,MyRequest 是輸入引數型別,MyResponse 是輸出引數型別。 rpc MyMethod (MyRequest) returns (MyResponse); // 伺服器流式方法 rpc ServerStreamingMethod(Request1) returns (stream Response1); // 客戶端流式方法 rpc ClientStreamingMethod(stream Request2) returns (Response2); // 雙向流式方法 rpc BidirectionalStreamingMethod(stream Request3) returns (stream Response3); } message MyRequest { repeated int32 num = 10; } message MyResponse { repeated string strs = 10; } message Request1 { string Message = 1; } message Response1 { string Message = 1; } message Request2 { string Message = 1; } message Response2 { string Message = 1; } message Request3 { string Message = 1; } message Response3 { string Message = 1; }
syntax = "proto3"; package Calculator; import "Protos/Calculator.proto"; service FirstService { rpc MyMethod (MyRequest1) returns (MyResponse); } message MyRequest1 { repeated int32 num = 10; }
多個.proto檔案間是可以呼叫的
4.新增.proto檔案生成的檔案編寫服務端和客戶端程式碼
.proto檔案生成的檔案位置 新增到客戶端和服務端
5.服務端程式碼
using Calculator; using Grpc.Core; class CalculatorServiceImpl : CalculatorService.CalculatorServiceBase { /// <summary> /// 釋出響應 /// </summary> /// <param name="request"></param> /// <param name="context"></param> /// <returns></returns> public override async Task<MyResponse> MyMethod(MyRequest request, ServerCallContext context) { MyResponse myResponse = new MyResponse(); foreach (int i in request.Num) { myResponse.Strs.Add(i.ToString()); } return myResponse; } /// <summary> /// 伺服器流(Server Streaming) /// </summary> /// <param name="request"></param> /// <param name="responseStream"></param> /// <param name="context"></param> /// <returns></returns> public override async Task ServerStreamingMethod(Request1 request, IServerStreamWriter<Response1> responseStream, ServerCallContext context) { for (int i = 0; i < 10; i++) { Response1 response = new Response1 { Message = request.Message + $"Message {i}" }; await responseStream.WriteAsync(response); await Task.Delay(500); // 模擬每秒傳送一次資料 } } /// <summary> /// 客戶端流(Client Streaming) /// </summary> /// <param name="requestStream"></param> /// <param name="context"></param> /// <returns></returns> public override async Task<Response2> ClientStreamingMethod(IAsyncStreamReader<Request2> requestStream, ServerCallContext context) { string str = ""; while (requestStream.MoveNext().Result) { str += requestStream.Current.Message; Console.WriteLine(requestStream.Current.Message); } return new Response2 { Message = str }; } /// <summary> /// 雙向流(Bidirectional Streaming) /// </summary> /// <param name="requestStream"></param> /// <param name="responseStream"></param> /// <param name="context"></param> /// <returns></returns> public override async Task BidirectionalStreamingMethod(IAsyncStreamReader<Request3> requestStream, IServerStreamWriter<Response3> responseStream, ServerCallContext context) { while (requestStream.MoveNext().Result) { // 處理客戶端傳送的請求 Console.WriteLine(requestStream.Current.Message); Response3 response = new Response3 { Message = requestStream.Current.Message + "abc" }; await responseStream.WriteAsync(response); // 傳送響應 await Task.Delay(500); } } } class Program { static void Main(string[] args) { const int Port = 50051; Server server = new Server { Services = { CalculatorService.BindService(new CalculatorServiceImpl()) }, Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) } }; server.Start(); Console.WriteLine("Calculator server listening on port " + Port); Console.WriteLine("Press any key to stop the server..."); Console.ReadKey(); server.ShutdownAsync().Wait(); } }
6.客戶端程式碼
using Calculator; using Grpc.Core; class Program { const string ServerAddress = "localhost"; const int Port = 50051; static void Main(string[] args) { MyMethod(); ServerStreamingMethod(); SelfIncreaseClient(); BidirectionalStreamingMethod(); Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } /// <summary> /// 釋出響應 /// </summary> private static void MyMethod() { Channel channel = new Channel($"{ServerAddress}:{Port}", ChannelCredentials.Insecure); var client = new CalculatorService.CalculatorServiceClient(channel); MyRequest myRequest = new MyRequest { Num = { 1, 2, 3, 4 } }; MyResponse myResponse = client.MyMethod(myRequest); Console.WriteLine($"Result: {myResponse.Strs}"); channel.ShutdownAsync().Wait(); } /// <summary> /// 伺服器流(Server Streaming) /// </summary> private static void ServerStreamingMethod() { Channel channel = new Channel($"{ServerAddress}:{Port}", ChannelCredentials.Insecure); var client = new CalculatorService.CalculatorServiceClient(channel); Request1 request1 = new Request1 { Message = "ceshi" }; AsyncServerStreamingCall<Response1> response1s = client.ServerStreamingMethod(request1); while (response1s.ResponseStream.MoveNext().Result) { Console.WriteLine(response1s.ResponseStream.Current.Message); } channel.ShutdownAsync().Wait(); } /// <summary> /// 客戶端流(Client Streaming) /// </summary> private static async void SelfIncreaseClient() { Channel channel = new Channel($"{ServerAddress}:{Port}", ChannelCredentials.Insecure); var client = new CalculatorService.CalculatorServiceClient(channel); var call = client.SelfIncreaseClient(); for (int i = 0; i < 10; i++) { await call.RequestStream.WriteAsync(new Request2() { Message = $"第{i}個" }); await Task.Delay(500); } await call.RequestStream.CompleteAsync(); Console.WriteLine($"Result: {call.ResponseAsync.Result.Message}"); channel.ShutdownAsync().Wait(); } /// <summary> /// 雙向流(Bidirectional Streaming) /// </summary> private static async void BidirectionalStreamingMethod() { Channel channel = new Channel($"{ServerAddress}:{Port}", ChannelCredentials.Insecure); var client = new CalculatorService.CalculatorServiceClient(channel); var call = client.BidirectionalStreamingMethod(); for (int i = 1; i <= 5; i++) { // 傳送請求 await call.RequestStream.WriteAsync(new Request3 { Message = i.ToString() }); await Task.Delay(500); } await call.RequestStream.CompleteAsync(); while (call.ResponseStream.MoveNext().Result) { // 處理伺服器傳送的響應 Console.WriteLine(call.ResponseStream.Current.Message); } channel.ShutdownAsync().Wait(); } }
7.Demo示例
原文連結:https://blog.csdn.net/qq1084517825/article/details/134272985