grpc的流模式

gRPC提供4种流模式来实现客户端和服务器之间的数据传输。

简单RPC

简单 RPC 是最基本的模式,客户端发送一个请求,服务器返回一个响应

使用场景:

  1. 查询信息:例如查询某个商品的详细信息。
  2. 状态检查:检查某个资源或服务的当前状态。
syntax = "proto3";

option csharp_namespace = "GrpcService_Server";

package demo;

service DemoGreeter {
  rpc Login (LoginRequest) returns (LoginResponse);
}

message LoginRequest {
  string account = 1;
  string password = 2;
}

message LoginResponse {
  string message = 1;
}
public class DemoService : GrpcService_Server.DemoGreeter.DemoGreeterBase
{
    public override Task<LoginResponse> Login(LoginRequest request, ServerCallContext context)
    {
        return Task.FromResult(new LoginResponse
           {
               Message = $"欢迎 {request.Account}登录系统 "
           });
    }
}
 public async Task TestgRPCService()
 {
     using (var channel = GrpcChannel.ForAddress("http://localhost:5200"))
     {
         DemoGreeterClient client = new DemoGreeterClient(channel);

         Console.WriteLine("-----------------普通调用-----------------");
         {
             LoginResponse loginResponse = client.Login(new LoginRequest()
             {
                 Account = "admin",
                 Password = "123456"
             });
             Console.WriteLine($"普通调用:服务端返回消息:{loginResponse.Message}");

             LoginResponse loginResponseAsync = await client.LoginAsync(new LoginRequest()
             {
                 Account = "test",
                 Password = "123456"
             });
             Console.WriteLine($"普通调用:服务端返回消息:{loginResponseAsync.Message}");
         }
     }
 }

客户端流式RPC

客户端流式 RPC 中,客户端发送一系列请求,服务器接收完所有请求后返回一个响应这种模式适合客户端需要分多次发送数据,服务器进行批量处理的场景。

使用场景:

  1. 数据上传:当客户端需要上传大量数据时,为了避免一次性传输可能导致的内存问题或网络拥塞,可以采用客户端流式 RPC。例如,在视频上传应用中,客户端将视频文件分割成多个小块,依次发送给服务器,服务器在接收到所有小块后进行合并和存储。
  2. 实时数据收集:在一些需要实时收集数据的场景中,客户端会不断产生数据并发送给服务器。比如,在物联网应用中,传感器会持续收集环境数据(如温度、湿度、光照等),并将这些数据分多次发送给服务器,服务器在收集完一定数量的数据后进行分析和处理。
syntax = "proto3";

option csharp_namespace = "GrpcService_Server";

package demo;

service DemoGreeter {
  // 客户端流式 RPC 方法
  rpc SayHelloClientStream (stream SayHelloClientRequest) returns (SayHelloClientHelloReply);
}
message SayHelloClientRequest {
  string name = 1;
}

message SayHelloClientHelloReply {
  string message = 1;
}
 public class DemoService : GrpcService_Server.DemoGreeter.DemoGreeterBase
 {
     public override async Task<SayHelloClientHelloReply> SayHelloClientStream(IAsyncStreamReader<SayHelloClientRequest> requestStream, ServerCallContext context)
     {
         var names = new List<string>();
         while (await requestStream.MoveNext())
         {
             names.Add(requestStream.Current.Name);
         }
         return new SayHelloClientHelloReply
         {
             //把客户端传过来的姓名拼接起来输出
             Message = "Hello, " + string.Join(", ", names)
         };
     }
 }
 public async Task TestgRPCService()
 {
     using (var channel = GrpcChannel.ForAddress("http://localhost:5200"))
     {
         DemoGreeterClient client = new DemoGreeterClient(channel);

         Console.WriteLine("-----------------客户端流式RPC-----------------");
         using var call = client.SayHelloClientStream();
         await call.RequestStream.WriteAsync(new SayHelloClientRequest { Name = "Jack"});
         await call.RequestStream.WriteAsync(new SayHelloClientRequest { Name = "Tom" });
         await call.RequestStream.CompleteAsync();
         var response = await call;
         Console.WriteLine("Greeting: " + response.Message);
     }
 }

服务端流式RPC

服务器流式 RPC 中,客户端发送一个请求,服务器返回一系列响应这种模式适合服务器需要分多次返回数据给客户端的场景。

使用场景:

  1. 数据下载:当服务器需要向客户端传输大量数据时,采用服务器流式 RPC 可以避免一次性传输带来的问题。例如,在文件下载应用中,服务器将文件分成多个小块,依次发送给客户端,客户端可以边接收边处理。
  2. 实时数据推送:在需要实时更新数据的场景中,服务器可以通过服务器流式 RPC 不断向客户端推送最新数据。比如,在股票交易应用中,客户端向服务器请求某只股票的实时行情,服务器会持续返回该股票的价格、成交量等信息,客户端可以实时更新显示。
syntax = "proto3";

option csharp_namespace = "GrpcService_Server";

package demo;

service DemoGreeter {
  // 服务器流式 RPC 方法
  rpc SayHelloServerStream (SayHelloServerRequest) returns (stream SayHelloServerReply);
}

message SayHelloServerRequest {
  string name = 1;
}

message SayHelloServerReply {
  string message = 1;
}
public class DemoService : GrpcService_Server.DemoGreeter.DemoGreeterBase
 {
    public override async Task SayHelloServerStream(SayHelloServerRequest request, IServerStreamWriter<SayHelloServerReply> responseStream, ServerCallContext context)
    {
        for (int i = 0; i < 3; i++)
        {
            await responseStream.WriteAsync(new SayHelloServerReply
            {
                Message = $"Hello {request.Name} - {i}"
            });
            await Task.Delay(1000);
        }
    }
}
 public async Task TestgRPCService()
 {
     using (var channel = GrpcChannel.ForAddress("http://localhost:5200"))
     {
         DemoGreeterClient client = new DemoGreeterClient(channel);

         Console.WriteLine("-----------------服务端流式RPC-----------------");
         using var call = client.SayHelloServerStream(new SayHelloServerRequest { Name = "World" });
         await foreach (var response in call.ResponseStream.ReadAllAsync())
         {
            Console.WriteLine("Greeting: " + response.Message);
         }
     }
 }

双向流式RPC

双向流式 RPC 中,客户端和服务器可以同时发送和接收消息。适合需要实时交互的场景。

使用场景:

  1. 实时通信:在即时通讯应用中,如聊天软件,客户端和服务器可以通过双向流式 RPC 实现实时消息的发送和接收。客户端可以随时发送消息给服务器,服务器也可以将其他用户的消息实时推送给客户端。
  2. 协作式应用:在一些需要多人协作的应用中,如在线文档编辑、多人游戏等,双向流式 RPC 可以实现实时的数据同步和交互。例如,在在线文档编辑应用中,多个用户可以同时对文档进行编辑,服务器会将每个用户的编辑操作实时同步给其他用户。
syntax = "proto3";

option csharp_namespace = "GrpcService_Server";

package demo;

service DemoGreeter {
  // 双向流式 RPC 方法
  rpc SayHelloBidirectionalStream (stream SayHelloBidirectionalRequest) returns (stream SayHelloBidirectionalReply);
}

message SayHelloBidirectionalRequest {
  string name = 1;
}

message SayHelloBidirectionalReply {
  string message = 1;
}
public class DemoService : GrpcService_Server.DemoGreeter.DemoGreeterBase
 {
    public override async Task SayHelloBidirectionalStream(IAsyncStreamReader<SayHelloBidirectionalRequest> requestStream, IServerStreamWriter<SayHelloBidirectionalReply> responseStream, ServerCallContext context)
 {
     await foreach (var request in requestStream.ReadAllAsync())
     {
         await responseStream.WriteAsync(new SayHelloBidirectionalReply
         {
             Message = $"Hello {request.Name}"
         });
     }
 }
}
 public async Task TestgRPCService()
 {
     using (var channel = GrpcChannel.ForAddress("http://localhost:5200"))
     {
         DemoGreeterClient client = new DemoGreeterClient(channel);

         Console.WriteLine("-----------------双向流式RPC-----------------");
         using var call = client.SayHelloBidirectionalStream();
         var responseTask = Task.Run(async () =>
         {
             await foreach (var response in call.ResponseStream.ReadAllAsync())
             {
                 Console.WriteLine("Greeting: " + response.Message);
             }
         });
         await call.RequestStream.WriteAsync(new SayHelloBidirectionalRequest { Name = "Jack" });
         await call.RequestStream.WriteAsync(new SayHelloBidirectionalRequest { Name = "Tom" });
         await call.RequestStream.CompleteAsync();
         await responseTask;
     }
 }

posted @ 2025-03-27 14:56  相遇就是有缘  阅读(51)  评论(0)    收藏  举报